4

我编写了一个 Haskell 函数,它计算给定列表中每个数字的阶乘并将其打印到屏幕上。

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

该功能有效,但我发现第三行有点混乱。为什么编译器(GHC)没有报告错误,因为“putStrLn”(准?)函数之前没有“do”?如果我从第 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是一种将这些 monad 串在一起的便捷方式,没有其他丑陋的语法。

如果您在 中只有一个语句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();
}

do在 Haskell 中的工作方式相同。


也许查看 factPrint 的类型会有所帮助,然后重构以使用模式匹配:

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

所以,如果 factPrint 返回IO (),并且类型putStrLn ""IO (),那么对于factPrint []equal是完全合法的putStrLn ""。不需要do——事实上,你可以说factPrint [] = return ()你是否不想要尾随的换行符。

于 2009-10-20T20:50:12.180 回答
4

do用于将多个单子表达式联系在一起。仅后跟一个表达式时,它没有效果。

要使 if 格式正确,只需 then 子句和 else 子句具有相同的类型。由于这两个子句都具有这种类型IO ()

于 2009-10-20T08:54:53.080 回答
3

do 关键字用于排序,do如果每个分支都是单个语句,则 Haskell 中的 if-then-else 根本不需要包含 a 。

if a
  then b
  else c

您需要do在您的示例中使用,因为您正在对 else 分支上的两个操作进行排序。如果您省略dothenfactPrint(tail list)语句被认为不是函数的一部分,因此编译器会抱怨,因为它遇到了意外的语句。

于 2009-10-20T08:51:59.993 回答