Haskell-返回用户输入整数的循环
我想写一个函数,当被调用时,它会不断地请求用户输入,直到输入可以被读取为整数为止(此时整数返回到一个可能的do块,在该块中函数首先被调用) 我的代码在这里:Haskell-返回用户输入整数的循环,haskell,recursion,io,Haskell,Recursion,Io,我想写一个函数,当被调用时,它会不断地请求用户输入,直到输入可以被读取为整数为止(此时整数返回到一个可能的do块,在该块中函数首先被调用) 我的代码在这里: lp_reqInt = do input1 <- getLine if ((readMaybe input1 :: Maybe Int) == Nothing) then do putStrLn "(integer input required, please try ag
lp_reqInt =
do
input1 <- getLine
if ((readMaybe input1 :: Maybe Int) == Nothing)
then do
putStrLn "(integer input required, please try again)"
lp_reqInt
else let output = fromMaybe (-666) (readMaybe input1 :: Maybe Int)
return output
lp_需求=
做
input1您似乎有点误解了do
-表示法的工作原理
我会给你一个“正确”的版本,我们可以解决这个问题:
lp_reqInt = do
input1 <- getLine
let maybeInput = readMaybe input1 :: Maybe Int
if maybeInput == Nothing
then do putStrLn "(integer input required, please try again)"
lp_reqInt
else return $ (\(Just x) -> x) maybeInput
lp_requint=do
输入1 x)可输入
注意顶部的let
-语句。我可以在这里执行let
-语句,而不是在-语句中执行let
-,因为它位于do
-块的顶层。当您编写let output=fromMaybe(…)
时,它不在do
-块的顶层,而是在if
-语句的第二部分,因此它将不起作用
正是因为这个原因,您得到了一个解析错误:GHC期望在
中出现一个附带的 您似乎有点误解了符号是如何工作的
我会给你一个“正确”的版本,我们可以解决这个问题:
lp_reqInt = do
input1 <- getLine
let maybeInput = readMaybe input1 :: Maybe Int
if maybeInput == Nothing
then do putStrLn "(integer input required, please try again)"
lp_reqInt
else return $ (\(Just x) -> x) maybeInput
lp_requint=do
输入1 x)可输入
注意顶部的let
-语句。我可以在这里执行let
-语句,而不是在-语句中执行let
-,因为它位于do
-块的顶层。当您编写let output=fromMaybe(…)
时,它不在do
-块的顶层,而是在if
-语句的第二部分,因此它将不起作用
正是因为这个原因,您得到了一个解析错误:GHC期望在
中出现一个附带的 另一个答案讨论了问题所在以及最小修复。除了让您继续编写代码的最简单的事情之外,我认为展示惯用的修复方法可能也很有趣,即使用模式匹配而不是if
。因此:
lp_reqInt :: IO Int
lp_reqInt = do
input1 <- getLine
case readMaybe input1 of
Nothing -> do
putStrLn "(integer input required, please try again)"
lp_reqInt
Just n -> return n
lp_需求::IO需求
lp_requint=do
输入1 do
putStrLn“(需要整数输入,请重试)”
lp_需求
只需n->返回n
这不需要在fromaybe
中使用奇怪的回退-666
,这很好。使用模式匹配而不是(==)
还有一个更微妙的优势:它不需要底层类型具有Eq
实例。对于Int
有一个,因此此代码没有优势,但在其他情况下,它可能更重要。我还将字体签名提升到了顶层;关于这个习语的进一步讨论。另一个答案讨论了哪里出了问题,以及最小的修复。除了让您继续编写代码的最简单的事情之外,我认为展示惯用的修复方法可能也很有趣,即使用模式匹配而不是if
。因此:
lp_reqInt :: IO Int
lp_reqInt = do
input1 <- getLine
case readMaybe input1 of
Nothing -> do
putStrLn "(integer input required, please try again)"
lp_reqInt
Just n -> return n
lp_需求::IO需求
lp_requint=do
输入1 do
putStrLn“(需要整数输入,请重试)”
lp_需求
只需n->返回n
这不需要在fromaybe
中使用奇怪的回退-666
,这很好。使用模式匹配而不是(==)
还有一个更微妙的优势:它不需要底层类型具有Eq
实例。对于Int
有一个,因此此代码没有优势,但在其他情况下,它可能更重要。我还将字体签名提升到了顶层;对于这个习语的进一步讨论。前面的答案很好,但我只想用另一种合理的方法来扩展这个主题,让那些最终在这里搜索的不是OP想要的东西,而是相关的东西
由于主题提到了用户输入(IO
)和整数(Maybe Int
),我们最终得到了类似IO(Maybe Int)
的类型。这些类型在Monad转换器下表达得最好,即maybetio Int
,它们也可以很好地充当Alternative
类成员
Haskell为这些情况提供了极好的解决方案,因此我们可以像这样处理相同的问题
import Control.Monad (msum)
import Control.Monad.Trans.Maybe
import Control.Monad.Trans (lift)
import Text.Read (readMaybe)
lp_reqInt :: MaybeT IO Int
lp_reqInt = msum . repeat $ (lift . putStrLn) "Enter an integer.." >>
(MaybeT $ readMaybe <$> getLine)
前面的答案很好,但我只是想用另一种合理的方法来扩展这个主题,让那些最终在这里搜索OP要求的内容,而不是相关的内容的人
由于主题提到了用户输入(IO
)和整数(Maybe Int
),我们最终得到了类似IO(Maybe Int)
的类型。这些类型在Monad转换器下表达得最好,即maybetio Int
,它们也可以很好地充当Alternative
类成员
Haskell为这些情况提供了极好的解决方案,因此我们可以像这样处理相同的问题
import Control.Monad (msum)
import Control.Monad.Trans.Maybe
import Control.Monad.Trans (lift)
import Text.Read (readMaybe)
lp_reqInt :: MaybeT IO Int
lp_reqInt = msum . repeat $ (lift . putStrLn) "Enter an integer.." >>
(MaybeT $ readMaybe <$> getLine)
您的let
语句需要in
关键字,因为它不在do
块中。@4castle您将放在关键字中的确切位置?in
中的将在返回之前。然而,case
在这里比if
更好,因为您可以对readMaybe input1
的结果进行模式匹配。您的let
语句需要in
关键字,因为它不在do
块中。@4castle您将放在关键字中的确切位置?将放在关键字中在返回之前向右走
。但是,case
在这里比if
更好,因为您可以对readMaybe input1
的结果进行模式匹配。