4

与えられたリストのすべての数の階乗を計算し、それを画面に出力するHaskell関数を作成しました。

factPrint list =
if null list
    then putStrLn ""
    else do putStrLn ((show.fact.head) list)
        factPrint (tail list)

関数は機能しますが、3行目は少しわかりにくいです。「putStrLn」(準?)関数の前に「do」がないのに、コンパイラ(GHC)がエラーを報告しないのはなぜですか?4行目から「do」を省略すると、期待どおりにエラーが表示されます。

私はHaskellとその方法にまったく慣れていないので、過度に愚かなことを言った場合はご容赦ください。

4

4 に答える 4

11
do putStrLn ((show.fact.head) list)
   factPrint (tail list)

実際には別の書き方です

putStrLn ((show.fact.head) list) >> factPrint (tail list)

つまり、

putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)

表記法は、このdo他の醜い構文なしで、これらのモナドをつなぎ合わせる便利な方法です。

内にステートメントが1つしかない場合はdo、何もつなぎ合わせていないため、doは冗長です。

于 2009-10-20T08:51:46.080 に答える
5

Haskellを初めて使用する場合は、Cのような言語でdo必要な中括弧に似ていると考えてください。if

if (condition)
  printf("a"); // braces not required
else {
  printf("b"); // braces required
  finish();
}

doHaskellでも同じように機能します。


たぶん、factPrintのタイプを調べてから、パターンマッチングを使用するようにリファクタリングすると役立つでしょう。

factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
  putStrLn (show.fact.head) list
  factPrint (tail list)

したがって、factPrintがを返しIO ()、のタイプがでputStrLn ""ある場合、等しいIO ()ことは完全に合法です。必須ではありません。実際、末尾の改行が必要ないかどうかを言うことができます。factPrint []putStrLn ""dofactPrint [] = return ()

于 2009-10-20T20:50:12.180 に答える
4

do複数のモナディック表現を結び付けるために使用されます。単一の式のみが続く場合は効果がありません。

ifが整形式であるためには、then節とelse節が同じタイプである必要があるだけです。両方の句がタイプを持っているので、IO ()これが当てはまります。

于 2009-10-20T08:54:53.080 に答える
3

dodoキーワードは順序付けに使用されます。たとえば、各ブランチが単一のステートメントである場合、Haskellのif-then-elseにaを含める必要はありません。

if a
  then b
  else c

doelseブランチで2つの操作をシーケンス処理しているため、この例ではを必要とします。dothenを省略すると、factPrint(tail list)ステートメントは関数の一部ではないと見なされるため、予期しないステートメントが検出されたため、コンパイラーは文句を言います。

于 2009-10-20T08:51:59.993 に答える