代码之家  ›  专栏  ›  技术社区  ›  Jamin

Haskell-在用其中一个验证后继续执行下一个操作

  •  0
  • Jamin  · 技术社区  · 6 年前

    我是Haskell的新手,使用do符号来验证用户的选择。

    userChoice :: String -> Either String String
    userChoice option
        | option == "1" = Right "You proceed with option 1."
        | option == "2" = Right "You proceed with option 2"
        | option == "3" = Right "You proceed with option 3"
        | option == "4" = Right "You proceed with option 4"
        | otherwise = Left $ "\n\nInvalid Option...\nWhat would you like to do?\n" ++ displayOptions(0)
    
    displayOptions :: Int -> String
    displayOptions option
        | option == 0 = "1 - Option 1\n2 - Option 2\n3 - Option 3\n4 - Option 4"
        | otherwise = "invalid"
    
    main = do
        putStrLn "Welcome."
        let start startMessage = do
            putStrLn startMessage
            let ask message = do
                putStrLn message
                choice <- getLine
                either ask ask $ userChoice(choice)
            ask $ "What would you like to do?\n" ++ displayOptions(0)
        start "Choose a number between 1-4."
    

    这很好,但是在用户选择了正确的选项之后,我想继续程序的下一部分。我可以使用return,但是我失去了用户选择的选项。

    main = do
        putStrLn "Welcome."
        let start startMessage = do
            putStrLn startMessage
            let ask message = do
                putStrLn message
                choice <- getLine
                either ask return $ userChoice(choice)
            ask $ "What would you like to do?\n" ++ displayOptions(0)
        start "Choose a number between 1-4."
    
        -- putStrLn userChoice2(choice)
    
        let continue continueMessage = do
            putStrLn continueMessage
            let ask message = do
                putStrLn message
                choice <- getLine
                either continue continue $ userChoice(choice)
            ask $ "What would you like to do?"
        continue "We are now here..."
    

    如果我尝试将continue作为正确的选项,那么它会抛出一个范围错误。类似地,如果我使用return并尝试为userChoice创建一个原始的克隆函数,我将无法再访问choice所在的范围。

    userChoice2 :: String -> String
    userChoice2 option
        | option == "1" = "You proceed with option 1."
        | option == "2" = "You proceed with option 2"
        | option == "3" = "You proceed with option 3"
        | option == "4" = "You proceed with option 4"
        | otherwise = "\n\nInvalid Option...\nWhat would you like to do?\n" ++ displayOptions(0)
    

    1 回复  |  直到 6 年前
        1
  •  2
  •   jberryman    6 年前

    听起来您只需要绑定monad中返回的值 start ,如下所示:

    main = do
        putStrLn "Welcome."
        let start startMessage = do
            putStrLn startMessage
            let ask message = do
                putStrLn message
                choice <- getLine
                either ask return $ userChoice(choice)
            ask $ "What would you like to do?\n" ++ displayOptions(0)
    
        -- THE NEW BIT I ADDED:
        opt <- start "Choose a number between 1-4."
        putStrLn opt   -- THIS PRINTS "You proceed with ..."
    
        -- SNIP
    

    你可以读到关于“脱糖”的书 do 符号”来学习如何将其转换为lambdas和 Monad 班级( >>= return ).


    您可以使用(而且应该更喜欢)模式匹配,而不是保护和 == Eq 类,而不是所有类型都实现)。例如。

    userChoice2 option = case option of
        "1" -> "You proceed with option 1."
        "2" -> "You proceed with option 2"
    

    记住在haskell中调用 foo a b foo a b foo(a,b)

    打开警告是非常有帮助的(无论是在学习时还是在生产代码基础上),例如,在这里,我在打开警告后在ghci中加载您的文件 -Wall

    Prelude> :set -Wall
    Prelude> :l k.hs
    [1 of 1] Compiling Main             ( k.hs, interpreted )
    
    k.hs:15:1: warning: [-Wmissing-signatures]
        Top-level binding with no type signature: main :: IO b
       |
    15 | main = do
       | ^^^^
    
    k.hs:24:5: warning: [-Wunused-do-bind]
        A do-notation statement discarded a result of type ‘String’
        Suppress this warning by saying
          ‘_ <- start "Choose a number between 1-4."’
       |
    24 |     start "Choose a number between 1-4."
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Ok, one module loaded.
    

    注意它警告你 开始 IO String String 值,这确实是一个错误。如果你真的想放弃你可以使用的值 void