如何在不执行它们的情况下绑定两个 IO () monad?
How can I bind two IO () monads without executing them?
在下面的代码中,我使用 >>
将 IO 操作连接在一起。但是 AFAIU,m1>>m2
被脱糖为 m1>>=(\_.m2)
,因此它在绑定时立即执行第一个 IO 操作。我希望所有的打印都发生在 main 中,即打印语句不应该与输入语句交错 ("Enter Code")。因为 do
不允许我 return 除 IO 之外的任何其他 monad,例如 [IO ()]
。怎样才能得到想要的打印效果?
f :: [Int] -> IO ()
f inventory = do
putStrLn "Enter Code\n"
x <- getLine
let idx = nameToIndex x
putStrLn "Quantity\n"
y <- getLine
putStrLn "More?\n"
c <- getChar
let q = (read y :: Int)
let curM = if inventory !! idx >= q then (putStrLn "sdaf\n") else (putStrLn "Overflow!\n")
if c == 'Y' then curM>>(f (update inventory idx)) else curM
main = f [1, 2]
我不是 100% 确定我理解这个问题,但我认为它是这样的:您想与用户进行一些交互,存储有关交互的信息,然后将所有信息显示在在整个交互结束时一次。
这是您的代码的一个非常简化的版本,它跳过了所有业务逻辑,只是不断询问用户是否要继续。
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> putStrLn "Okay, let's continue." >> prompt
_ -> return ()
main = prompt
我 认为 您要求的效果是延迟 "Okay, let's continue." 的显示,直到用户停止点击 "y"。那没问题。有很多方法可以做到这一点。最灵活的是有prompt
return它完成后要执行的动作:
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> do
act <- prompt
return (putStrLn "Okay, let's continue." >> act)
_ -> return (return ())
main = do
act <- prompt
act
(也有一些组合器可以使这段代码更紧凑。)但我不喜欢这种设计;这让我们很难反思 prompt
的结果。一种更专业但也更易于维护的方法是 return 一些描述交互的数据,然后调用者可以将其转换为 IO
总结事物的动作。在这种情况下,字符串列表似乎是一个合适的描述。
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> do
results <- prompt
return ("Okay, let's continue." : results)
_ -> return []
main = do
results <- prompt
mapM_ putStrLn results
希望这个解释足够清楚,以便您可以将这个想法与更复杂的业务逻辑结合起来。
在下面的代码中,我使用 >>
将 IO 操作连接在一起。但是 AFAIU,m1>>m2
被脱糖为 m1>>=(\_.m2)
,因此它在绑定时立即执行第一个 IO 操作。我希望所有的打印都发生在 main 中,即打印语句不应该与输入语句交错 ("Enter Code")。因为 do
不允许我 return 除 IO 之外的任何其他 monad,例如 [IO ()]
。怎样才能得到想要的打印效果?
f :: [Int] -> IO ()
f inventory = do
putStrLn "Enter Code\n"
x <- getLine
let idx = nameToIndex x
putStrLn "Quantity\n"
y <- getLine
putStrLn "More?\n"
c <- getChar
let q = (read y :: Int)
let curM = if inventory !! idx >= q then (putStrLn "sdaf\n") else (putStrLn "Overflow!\n")
if c == 'Y' then curM>>(f (update inventory idx)) else curM
main = f [1, 2]
我不是 100% 确定我理解这个问题,但我认为它是这样的:您想与用户进行一些交互,存储有关交互的信息,然后将所有信息显示在在整个交互结束时一次。
这是您的代码的一个非常简化的版本,它跳过了所有业务逻辑,只是不断询问用户是否要继续。
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> putStrLn "Okay, let's continue." >> prompt
_ -> return ()
main = prompt
我 认为 您要求的效果是延迟 "Okay, let's continue." 的显示,直到用户停止点击 "y"。那没问题。有很多方法可以做到这一点。最灵活的是有prompt
return它完成后要执行的动作:
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> do
act <- prompt
return (putStrLn "Okay, let's continue." >> act)
_ -> return (return ())
main = do
act <- prompt
act
(也有一些组合器可以使这段代码更紧凑。)但我不喜欢这种设计;这让我们很难反思 prompt
的结果。一种更专业但也更易于维护的方法是 return 一些描述交互的数据,然后调用者可以将其转换为 IO
总结事物的动作。在这种情况下,字符串列表似乎是一个合适的描述。
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> do
results <- prompt
return ("Okay, let's continue." : results)
_ -> return []
main = do
results <- prompt
mapM_ putStrLn results
希望这个解释足够清楚,以便您可以将这个想法与更复杂的业务逻辑结合起来。