【问题标题】:Guard inside 'do' block - haskell在'do'块内守卫 - haskell
【发布时间】:2020-05-03 19:36:55
【问题描述】:

我想写一个简单的游戏“猜数字”——尝试n。我想添加一些条件和命中。是否可以在 do 块内使用 guards

这是我的代码:

game = return()
game n = do putStrLn "guess number: 0-99"
            number<-getLine
            let y = read number
            let x =20
            | y>x = putStrLn "your number is greater than x"
            | y<x = putStrLn "your number is less than x"
            | y==x  putStrLn "U win!!"
            | otherwise = game (n-1)

已经出错了

error: parse error on input ‘|’

是否可以通过一些 空白 来解决,还是根本无法解决?

【问题讨论】:

    标签: haskell syntax do-notation guard-clause


    【解决方案1】:

    那里有很多问题。

    首先,你不能说 game =game n = ,所以删除 game = return () 行。 (您可能一直在尝试编写类型签名,但那不是。)

    其次,您不能在任意位置使用保护语法。与您所写内容最接近的有效内容是 multi-way if-expressions,它可以让您这样写:

    {-# LANGUAGE MultiWayIf #-}
    game n = do putStrLn "guess number: 0-99"
                number<-getLine
                let y = read number
                let x =20
                if
                  | y>x -> putStrLn "your number is greater than x"
                  | y<x -> putStrLn "your number is less than x"
                  | y==x-> putStrLn "U win!!"
                  | otherwise -> game (n-1)
    

    第三,Ord 类型类应该用于具有总顺序的类型,因此除非您使用像 NaN 这样的非法事物,否则您将始终拥有 y&gt;xy&lt;x 或 @987654329 之一@,因此永远不会输入otherwise

    第四,与&lt;==&gt; 比较是单一且缓慢的,因为它必须不断重复比较。而不是这样做,做这样的事情:

    case y `compare` x of
      GT -> _
      LT -> _
      EQ -> _
    

    【讨论】:

    • 它帮助我用“案例”解决了这个问题。感谢您的提示。
    【解决方案2】:

    do expression [Haskell-report] 仅由 exppat &lt;- explet … 语句组成,编译器将对这些语句进行脱糖处理。因此,如果没有一些语言扩展,您就不能在 do 块中编写守卫。此外,无论如何启用它可能不是一个好主意。例如,如果您想使用两个相邻的“防护块”怎么办?然后两者将“合并”,因此第一个街区的守卫已经(几乎)消除了所有案件。

    您可以在此处使用另一个let 子句:

    game :: IO ()
    game 0 = return ()
    game n = do
        putStrLn "guess number: 0-99"
        number <- getLine
        let y = read number
        let x = 20
        let action | y > x = putStrLn "your number is greater than x" >> game (n-1)
                   | y < x = putStrLn "your number is less than x" >> game (n-1)
                   | otherwise = putStrLn "U win!!"
        action

    请注意,原始问题中的otherwise 永远不会被触发,因为一个值小于、大于或等于另一个值。

    【讨论】:

    • 我稍微修改了一下,但游戏现在可以运行了。谢谢提示。
    【解决方案3】:

    您也可以只使用caseLambdaCase

    {-# LANGUAGE LambdaCase #-}
    
    game  :: Int -> IO ()
    game n = case n of
      0 -> putStrLn "used all attempts"
      n -> 
        putStrLn "guess a number: 0 - 99" >>
        (`compare` 20) . read <$> getLine >>= 
          \case 
            EQ -> putStrLn "U win"
            GT -> putStrLn "your number is greater than x" >> 
                  game (n - 1)
            LT -> putStrLn "your number is less than x" >> 
                  game (n - 1)
    

    【讨论】:

      【解决方案4】:

      其他答案非常有用。阅读这些让我看到你也可以调用一个函数来解决这个问题,例如

      game = do putStrLn "guess number: 0-99"
                number<-getLine
                let y = read number
                let x = 20
                action y x
             where
                 action y x 
                  | y>x = putStrLn "your number is greater than x" >> game
                  | y<x = putStrLn "your number is less than x" >> game
                  | otherwise = putStrLn "U win!!"
      

      【讨论】:

        猜你喜欢
        • 2016-07-31
        • 1970-01-01
        • 1970-01-01
        • 2019-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-03
        • 2017-07-26
        相关资源
        最近更新 更多