-1

在这几行中,错误一定很小,以至于我自己不会明白。

这是我的代码:

askName = do
  putStr "Type your name: "
  name <- getLine
  return name

sayHelloTo name = do
  when (null name) (name <- askName)

显然它给出了一个错误:

1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:9:30: parse error on input `<-'
Failed, modules loaded: none.

有什么建议吗?

编辑 1。

如果我这样写:

sayHelloTo name = do
  when (null name) (name2 <- askName)
4

2 回答 2

9

name2 <-语法是 do-notation 的一部分,只能在do块内使用。它也不是变量赋值 - 在引擎盖下它只是创建一个回调函数name2作为参数

也就是下面的代码:

do
    name2 <- monadicOp
    ...things...

脱糖成

monadicOp >>= (\name2 -> ...things... )

我希望这有助于清楚地表明您不会在 Haskell 中分配或改变它们。

无论如何,要解决您的特定问题,您可以做的就是使用 if-then-else (实际上相当于?:三元运算符)并返回适当的值。例如,以下函数使用递归来一次又一次地询问名称,直到它对结果满意为止

getNonEmptyName :: IO String
getNonEmptyName = do
    name <- getName
    if null name --note: indenting if statements in do blocks is tricky
       then getNonEmptyName
       else (return name)

或者,没有 do 符号糖:

getNonEmptyName = getName >>= (\name -> if (null name) then getNonEmptyName else (return name) )

这可能与您习惯的有所不同,但我想您应该能够在了解其工作原理后清除事物。基本上getNonEmptyName是 type IO String,这意味着它是一个 IO 动作 IO 动作,它在运行时产生一个字符串。if-then-else 部分也应该评估为一个IO String值,因为它的值将是 getNonEmptyName 的返回值。这一切正常,因为首先我们对 getNonEmptyName 进行递归调用(并根据需要提供 IP 字符串值),在 else 分支中,我们使用返回函数将常规字符串值(名称)提升为 IO 字符串。

于 2013-01-08T19:00:51.827 回答
4

目前尚不完全清楚sayHelloTo应该做什么或返回什么——它肯定不会修改name——但猜测一下,你可能意味着类似

 sayHelloTo :: String -> IO String
 sayHelloTo name
   | null name   = askName
   | otherwise   = return name
于 2013-01-08T18:53:32.933 回答