Haskell:whileM_变量范围?

时间:2017-12-13 22:51:25

标签: haskell

如何在其Bool后面的whileM_部分中使用作用域的变量?

例如:

guess :: IO ()
guess = do
  putStrLn "Please input your guess."
  whileM_
    (do
      guess <- getLine
      return (guess /= "secret"))
    (do
      putStrLn ("You guessed: " ++ guess)
      putStrLn ("And " ++ guess ++ " is wrong."))
  putStrLn "Right - Bye..."

guess不在第二个do块的范围内,因此无法使用。

如何将其纳入范围?

谢谢。

1 个答案:

答案 0 :(得分:4)

whileM_没有内置的实现方法。那个组合器真的有点限制;正如dfeuer所说,你应该使用递归自己编写循环。或者,使用实际上支持这种信息传递的循环结构:

guess :: IO ()
guess = do
  putStrLn "Please input your guess."
  whileJust_
    (do
      lastGuess <- getLine  -- don't use the name `guess` if that's already a global function name!
      return $ if lastGuess /= "secret"
                them Just lastGuess else Nothing )
    (\lastGuess -> do
      putStrLn $ "You guessed: " ++ lastGuess
      putStrLn $ "And " ++ lastGuess ++ " is wrong." )
  putStrLn "Right - Bye..."

但是 还可以在whileM_的条件和执行部分之间传递值。两个选项:

  • 特别是IO,您可以随时使用IORefs

    guess :: IO ()
    guess = do
      putStrLn "Please input your guess."
      bestGuess <- newIORef ""
      whileM_
        (do lastGuess <- getLine
            writeIORef bestGuess lastGuess
            return $ lastGuess /= "secret" )
        (do lastGuess <- readIORef bestGuess
            putStrLn $ "You guessed: " ++ lastGuess
            putStrLn $ "And " ++ lasyGuess ++ " is wrong." )
      putStrLn "Right - Bye..."
    

    这在Haskell中更为谨慎 - IORef基本上是一个可变变量 - 但有时它是明智的。绝对不是一个好主意。

  • 您可以代替IO使用具有纯功能状态变量的专用monad。这需要a monad transformer。这是一种稍微先进的技术,但对于复杂的应用程序可以很好地解决。