问题描述
我希望以下代码首先提示 start:
,然后等待用户响应,然后再回送先前的用户响应,然后等待新的用户响应:
I expected the following code to first prompt start:
, then wait for a user response, before echoing the previous user response back, and awaiting a new one:
import System.IO (hFlush, stdout)
import Control.Monad.Fix (mfix)
f :: [String] -> IO [String]
f = mapM $ \x -> putStr x >> putStr ": " >> hFlush stdout >> getLine
g x = f ("start":x)
main = mfix g
但是,在输入第一行后,它会在中无限期阻止线程。
But it gives the error thread blocked indefinitely in an MVar operation
after the first line is entered.
为什么会这样,我该如何解决它(原谅双关语)?
Why is this and how can I fix it (excuse the pun)?
推荐答案
不能工作的是在 mfix f
中只有一次在 f
中运行任何效果。这来自收紧规则
The reason why this can't work is that in mfix f
runs any effect in f
exactly once. This follows from the tightening rule
mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
特别是
in particular
mfix (\x -> a >> f x) = a >> mfix f
。因此,固定点仅针对一元操作内的纯粹(懒惰计算)值进行计算,而对于效果而言则不是 。在你的情况下,使用 mfix
要求打印/读取字符一次,以使输入等于输出,这是不可能的。对于 mfix
,这不是合适的用例。例如,您可以使用 mfix
和 IO
来构造 IO
就像。
for any correct instance of MonadFix
. So the fixed point is only computed for the pure (lazily computed) value inside the monadic action, not for the effects. In your case using mfix
asks for printing/reading characters just once in such a way that the input is equal to the output, which is impossible. This isn't a proper use case for mfix
. You'd use mfix
with IO
for example to construct a cyclic data structure in IO
like in these examples.
在你的情况下,你应该使用或类似的东西,而不是 mfix
。另请参阅。
In your case you should use iterateM_
or something similar rather than mfix
. see also iterate + forever = iterateM? Repeating an action with feedback.
这篇关于mfix不能按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!