在下面的代码中,我使用>>
将IO操作连接在一起。但是AFAIU,m1>>m2
被解除了m1>>=(\_.m2)
,因此它在绑定时正在执行第一个IO操作。我希望所有打印都发生在main中,即print语句不应与输入语句交错("输入代码")。由于do
不允许我返回除[IO ()]
之类的IO以外的任何其他monad。如何获得所需的打印效果?
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]
答案 0 :(得分:5)
我不是100%确定我理解这个问题,但我认为它是这样的:您想与用户进行一些互动,存储有关互动的信息,然后显示所有在整个互动结束时立即提供信息。
这是一个非常简化的代码版本,它会跳过所有业务逻辑,并不断询问用户是否要继续。
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> putStrLn "Okay, let's continue." >> prompt
_ -> return ()
main = prompt
我认为你要求的效果是延迟显示&#34;好的,让我们继续。&#34;直到用户停止按下&#34; y&#34;。这没问题。你可以通过很多方法做到这一点。最灵活的是让prompt
在完成后返回它想要执行的操作:
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
的结果进行反省。更专业但也更易于维护的方法是返回一些描述交互的数据,然后调用者可以将其转换为总结事物的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
希望这个解释很清楚,你可以将这个想法与更复杂的业务逻辑结合起来。