Haskell - 验证后继续下一步
Haskell - Continuing to next do after validating with either
我是 Haskell 的新手,我使用 do 表示法通过 Either 来验证用户的选择。
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 但我丢失了用户选择的选项。
举个例子,我可以在用户选择权限的时候把return放在这里,但是它不会说字符串"You proceed with option..."。
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..."
如果我尝试将继续作为正确的选项,那么它会抛出范围错误。同样,如果我使用 return 并尝试为 userChoice 创建一个原始的克隆函数,我将无法再访问范围 choice is in.
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)
有没有办法优雅地将它们链接在一起?
听起来您只需要绑定来自 start
的 monad 中返回的值,如下所示:
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
您可以阅读 "desugaring do
notation" 以了解它如何转换为 lambda 以及 Monad
class(>>=
和 return
)的方法。
其他一些建议:
您可以使用(并且应该更喜欢)模式匹配来代替守卫和 ==
(Eq
class 的一种方法,并非所有类型都实现)。例如
userChoice2 option = case option of
"1" -> "You proceed with option 1."
"2" -> "You proceed with option 2"
请记住,在 haskell 中,在 a
和 b
上调用 foo
的语法是 foo a b
而不是 foo(a,b)
打开警告(无论是在学习还是在生产代码库中)都非常有帮助,例如在这里,我在打开 -Wall
:
后将你的文件加载到 ghci 中
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.
请注意,它警告您 start
returns IO String
但您没有对 String
值执行任何操作,这确实是一个错误。如果您真的想丢弃该值,您可以使用 void
使其显式化并消除错误。
我是 Haskell 的新手,我使用 do 表示法通过 Either 来验证用户的选择。
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 但我丢失了用户选择的选项。
举个例子,我可以在用户选择权限的时候把return放在这里,但是它不会说字符串"You proceed with option..."。
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..."
如果我尝试将继续作为正确的选项,那么它会抛出范围错误。同样,如果我使用 return 并尝试为 userChoice 创建一个原始的克隆函数,我将无法再访问范围 choice is in.
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)
有没有办法优雅地将它们链接在一起?
听起来您只需要绑定来自 start
的 monad 中返回的值,如下所示:
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
您可以阅读 "desugaring do
notation" 以了解它如何转换为 lambda 以及 Monad
class(>>=
和 return
)的方法。
其他一些建议:
您可以使用(并且应该更喜欢)模式匹配来代替守卫和 ==
(Eq
class 的一种方法,并非所有类型都实现)。例如
userChoice2 option = case option of
"1" -> "You proceed with option 1."
"2" -> "You proceed with option 2"
请记住,在 haskell 中,在 a
和 b
上调用 foo
的语法是 foo a b
而不是 foo(a,b)
打开警告(无论是在学习还是在生产代码库中)都非常有帮助,例如在这里,我在打开 -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.
请注意,它警告您 start
returns IO String
但您没有对 String
值执行任何操作,这确实是一个错误。如果您真的想丢弃该值,您可以使用 void
使其显式化并消除错误。