`mfix`没有按预期工作

Cli*_*ton 5 monads haskell

我希望以下代码首先提示start:,然后等待用户响应,然后回显之前的用户响应,并等待新的响应:

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
Run Code Online (Sandbox Code Playgroud)

但它thread blocked indefinitely in an MVar operation在输入第一行后给出错误.

为什么这个以及如何解决它(请原谅双关语)?

Pet*_*lák 7

这不能起作用的原因是mfix ff一次运行任何效果.这是紧缩政策的结果

mfix (\x -> a >>= \y -> f x y)  =  a >>= \y -> mfix (\x -> f x y)
Run Code Online (Sandbox Code Playgroud)

特别是

mfix (\x -> a >> f x)  =  a >> mfix f
Run Code Online (Sandbox Code Playgroud)

对于任何正确的实例MonadFix.因此,固定点仅针对monadic动作中的纯(延迟计算)值计算,而不是针对效果计算.在您的情况下,使用mfix请求只打印/读取字符一次,使输入等于输出,这是不可能的.这不是一个正确的用例mfix.你会使用mfixIO例如以构建循环数据结构IO这些例子.

在你的情况下,你应该使用iterateM_或类似的东西,而不是mfix.另见iterate + forever = iterateM?通过反馈重复操作.


Ørj*_*sen 4

不幸的是,mfixIOmonad 中并不能真正产生这样的零碎列表。这是因为 monad 中的大多数操作都非常严格:在执行整个操作之前,IO它们不会产生结果的任何部分。特别是,在遍历完所有输入列表之前,mapMin不会返回其结果列表的任何部分,这使得这里没有希望以正确的方式喜结连理。IOmfix

一般来说,只有在整个操作完成之前不严格查看绑定值的情况下,mfixin才有效。这仍然一些可能的用途,例如仅使用可变单元周期来初始化数据结构。IOmfixnewIORef