1

数字のリストを取得し、厳密に増加/減少/定数シーケンスが続くかどうかを判断する簡単なプログラム(CCC 2012の2番目の質問)があります。例:Haskell:解析方法の影響を受けて怠惰

1 2 3 4 7 8 => Increasing 
5 1 -2 -100 => Decreasing 
9 9 9 9 9 9 => Constant 
1 2 3 4 5 0 => Nothing 

私はこれをコード化したときのスマートな方法によって完全に吹き飛んだ。何らかの理由で、私がstdinに対話形式で数字を入力したときに、私も終了する前に私に答えを与えていました!私はバグだと思ったが、ハスケルの怠け者(私は思う?)がそれ自体を取って、1230を入力した後で、結果がNothing、それでそれは喜んでそれを出力しました。私は

maybeRead :: (Read a) => String -> Maybe a 
maybeRead = fmap fst . listToMaybe . filter (null . dropWhile isSpace . snd) . reads 

parse :: (Read a) => [String] -> [a] 
parse xs = 
    let entries = map maybeRead xs 
    in if all isJust entries 
     then map fromJust entries 
     else [] 

として実装され、parseは、数値入力を読み取るより安全な方法であることを

let readings = parse $ lines input 

let readings = map (read :: (Read a, Num a) => String -> a) $ lines input 

を変更したとき

は残念ながら、それはもはやこれを行いません。

なぜですか?

EDIT:その他のコード

-- | Zip together adjacent list elements as pairs in a new list. 
zipPairs :: [a] -> [(a, a)] 
zipPairs xs = zip (init xs) (tail xs) 

-- | Return True if all elements of a given list are equal. 
constant :: (Eq a) => [a] -> Bool 
constant xs = all (== head xs) (tail xs) 

-- | Return the order that the elements of a list are sorted in, if they form 
-- a strictly increasing (Just LT), decreasing (Just GT) or constant (Just EQ) 
-- sequence. If there is no pattern, return Nothing. 
order :: (Ord a) => [a] -> Maybe Ordering 
order xs = 
    let orders = map (\(x, y) -> x `compare` y) (zipPairs xs) 
    in if constant orders then Just (head orders) else Nothing 

、その後mainに私が持っている

let readings = parse $ lines input 
putStrLn $ if null readings 
    then "bad input" 
    else case order readings of 
     Just EQ -> "Constant" 
     Just LT -> "Diving" 
     Just GT -> "Rising" 
     Nothing -> "Nothing" 
+1

+1;啓示の啓示のために+1)。 – gphilip

答えて

5

すべてのエントリはjustsている場合は、all isJust entriesチェックエントリのリスト全体を意味したエントリのリスト全体、 parseに戻る前に読まなければならない。

さて、なぜordersの長い説明は怠惰である - とすぐに、それは述語がFalseを返すの値に達するとFalseを返しall。したがって、constantは、頭に等しくないテールの値にヒットするとすぐにfalseを返します。 orderが返されるとすぐにconstantが返されるので、orderは遅延です。

私の最初の提案は文体です - ordersを計算するときにzipWith関数を見てください。 let orders = zipWith compare xs $ tail xsも同様に機能するはずです。

限り、懸念している、あなたの実際の問題を解決するとして、あなたはどちらかまたは両方の場合Just xJust yNothingを渡されたときData.Monad

liftM2 compareJust (compare x y)が返されますインポートする必要が

order xs = let orders = zipWith (liftM2 compare) xs $ tail xs 
      in if isJust (head orders) && constant orders 
       then head orders 
       else Nothing 

注意をしてみてくださいその引数はNothingです。

は、[Maybe Ordering]になりました。ordersが一定の場合(注:がMaybeで動作)、最初の要素がJustの場合は、最初の要素(既にMaybe Ordering)を返します。それ以外の場合は、Nothingを返してください。 isJust (head orders)コールなしでも可能ですが、Nothingが表示されるとすぐにそれを返す必要があります(そうでない場合は、すべてNothingのリストを指定すると、すべてがNothingであるかどうかがチェックされます)。

+0

私はこれまでこれをやろうとしていましたが、問題は、悪い入力が黙って気付かれないようにすることです。 「1」、「2」、「efyugf」、「3」と入力すると、すべてが破棄され、1-2-3と解釈されません。 – mk12

+0

この変更を行うと、以前と同じ動作を示すことは間違いありません。上記を避けながら私が望むことをする方法はありませんか? – mk12

+0

'1'、' 2'、 '1'、' efuas'で入力するとどうなりますか? 'parse'は' [] 'を返す必要があるかもしれないので、何も返せません。 '1:2:1:rest of list'を返し、' efuas'にヒットした場合、リストの最初の部分を「元に戻す」必要があります。これは意味をなさないものです。このため、 'parse'は何かを返す前にリスト全体を読み込むまで待たなければなりません。私が見ることができる唯一の解決策は、すべてを同じ関数に移動するか、エラーチェック制約を緩和することです。 – Retief

2

おそらくmapMaybeData.Maybeから使用できます。つまり、map readmapMaybe maybeReadと交換します。 mapMaybeは、その関数をリストにマップし、Nothingをフィルタリングし、残りのすべての値を抽出します。

+0

あなたはそうです、それはRetiefが提案したように、自分の 'map'と' filter isJust'を行うよりもきれいです。しかしそれはまだ理想的ではありません。 – mk12

+0

それは良い提案です - 私の 'map fromJust $ filter isJust $ map f'やリスト理解のほうがはるかに優れています。 – Retief

関連する問題