Haskell Guards涉及布尔运算和Do

时间:2018-11-24 02:13:17

标签: haskell

我刚开始使用Wikibook学习Haskell,到目前为止,我做的还不错,因为我已经在Visual Basic和Java方面学习了非常基础的HS课程,但是Haskell的某些奇特功能使我在合并更多内容时感到困惑比一个。其中一本Wikibook遇到了一个练习问题,即根据作为用户输入的特定名称编写三个不同的字符串。当使用if-then-else语句时,这很好,但是当我尝试使用防护时,我在第6行遇到了解析错误。

    main = do
        putStrLn "What is your name?"
        n <- getLine
        |(n == "Simon") || (n == "John") || (n == "Phil")
            = putStrLn "Help me make this stuff"
        |n == "Koen" = putStrLn "How is this a parse error"
        |otherwise "Line 11 looks fine to me"

Which reads " error: parse error on input ‘|’"
Is this a problem with the guard | or the operator ||? the error lists it is on 6:9 if that helps.

编辑:由于有人回答了我的第一个问题,因此我对一个非常相似的主题还有另一个问题。 Wikibooks Haskell教程已将此列为练习的另一种解决方案,使用where语句代替if-then-else:

main = do
  putStrLn "Hello, what is your name?"
  name <- getLine
  putStrLn (message name)
    where
    greatlanguage   = "I think Haskell is a great programming language."
    message "Simon" = greatlanguage
    message "John"  = greatlanguage
    message "Phil"  = greatlanguage
    message "Koen"  = "I think debugging Haskell is fun."
    message _       = "Sorry, I don't know you."

是否可以使用||?运算符如何以某种方式将3个Simon,John和Phil行压缩为单行?

3 个答案:

答案 0 :(得分:2)

只能将保护插入函数定义(以func a b | condition = ...的形式)和case块(以case x of pattern | condition -> ...的形式)中;您不能将它们插入do内,以阻止您尝试的方式。您将需要在此处使用if ... then ... else

答案 1 :(得分:2)

有很多方法可以解决这个问题。我建议您考虑将这段代码从do块移到它自己的函数中。

for n :: String -> IO ()
foo n | n == "Simon" ||
        n == "John"  ||
        n == "Phil"  = putStrLn "Help me make this stuff"
      | n == "Koen"  = putStrLn "How is this a parse error"
      |otherwise     = putStrLn "Line 11 looks fine to me"

然后在您的do块中调用它,

main = do
    putStrLn "What is your name?"
    n <- getLine
    foo n

另外,将辅助功能设置为“纯”可能更明智,

for n :: String -> String
foo n | n == "Simon" ||
        n == "John"  ||
        n == "Phil"  = "Help me make this stuff"
      | n == "Koen"  = "How is this a parse error"
      |otherwise     = "Line 11 looks fine to me"

并通过

进行调用
main = do
    putStrLn "What is your name?"
    n <- getLine
    putStrLn (foo n)

如果您愿意,也可以简化第一个后卫,

foo n | n `elem` ["Simon", "John", "Phil"] = "Help me make this stuff"
      | n == "Koen" = "How is this a parse error"
      |otherwise    = "Line 11 looks fine to me"

如果您真的想将其内联到do块中,则可以通过案例构建来适应其中一种解决方案,例如

main = do
    putStrLn "What is your name?"
    n <- getLine
    putStrLn $ case n of
      _ | n `elem` ["Simon", "John", "Phil"] -> "Help me make this stuff"
      _ | n == "Koen" -> "How is this a parse error"
      _               -> "Line 11 looks fine to me"

答案 2 :(得分:2)

为补充其他答案,我将添加两个选择(不一定是更好的选择)。

main = do
    putStrLn "What is your name?"
    n <- getLine
    case () of
       _ | n == "Simon" || n == "John" || n == "Phil"
            -> putStrLn "Help me make this stuff"
         | n == "Koen" 
            -> putStrLn "How is this a parse error"
         | otherwise
            -> putStrLn "Line 11 looks fine to me"

这需要打开MultiWayIf扩展名。

{-# LANGUAGE MultiWayIf #-}  --  at the top of the file

main = do
    putStrLn "What is your name?"
    n <- getLine
    if | n == "Simon" || n == "John" || n == "Phil"
          -> putStrLn "Help me make this stuff"
       | n == "Koen" 
          -> putStrLn "How is this a parse error"
       | otherwise
          -> putStrLn "Line 11 looks fine to me"

请记住,即使在otherwise之后,我们仍然需要->,否则会触发解析错误。