我写一个Haskell函数,计算在给定的列表并将其打印到屏幕阶乘每数目。

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

在功能工作,但我发现第三行有点混乱。 为什么没有编译器(GHC)报告一个错误就可以了,因为没有“做”的“putStrLn”(准?)函数之前? 如果我省略“做”从第4行,如所预期的错误弹出。

我是很新的Haskell和它的方式,所以请原谅我,如果我说了一些过于愚蠢。

有帮助吗?

解决方案

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符号是穿线这些单子在一起,而没有这种其他丑陋语法的方便的方法。

如果你只有do内的一个说法,那么你就没有任何东西串在一起,而do是多余的。

其他提示

如果你是新来的Haskell,认为do类似的所需括号if之后的类C语言:

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 []等于putStrLn ""完全合法的。没有do必需的 - 事实上,你可以只说factPrint [] = return ()如果你不想尾随换行

do用于配合多种一元表达式在一起。它随后当仅由单个表达没有影响。

有关的,如果是良好形成的,即当时-子句和else从句具有相同的类型,仅需要。由于两个条款不得不类型IO ()是这种情况。

在不关键字用于测序,如果 - 则 - 否则在Haskell不必包含do在所有如果每个分支是一个语句例如

if a
  then b
  else c

您需要在您的示例do因为你是你的else分支测序两个操作。如果省略do那么factPrint(tail list)声明被认为不是功能的一部分,因此为它遇到了一个意想不到的声明编译器会抱怨。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top