System.IO docs包含一个神秘的,未记录的函数fixIO
。 Its source只会增加神秘感:
fixIO :: (a -> IO a) -> IO a
fixIO k = do
m <- newEmptyMVar
ans <- unsafeInterleaveIO (takeMVar m)
result <- k ans
putMVar m result
return result
这似乎与取消引用NULL(从空的MVar读取)相当。的确,尝试一下:
import System.IO
main = fixIO $ \x -> putStrLn x >> return x
导致错误“线程在MVar操作中无限期阻塞”
除了Simon Peyton-Jones本人的15 year old message之外,搜索没有任何结果,他提供了上述来源,并希望它能使意思明确(而且我在这里)。
有人可以对此有所了解吗? fixIO做什么以及何时应该使用它?
答案 0 :(得分:12)
fixIO
是IO
相当于fix
。
您可能已经看到了斐波纳契序列的这个定义:
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
在fibs
的定义中重用fibs
变量来进行核心传输。它的工作原理是因为我们利用懒惰来定义fibs
之前需要使用的每个元素。
我们可以使用fix
执行相同操作,而无需为我们定义变量tying the knot:
fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)
如果你不特别需要保留整个斐波那契序列,那么这很方便,你只想知道它的第十个元素:
λ (fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) !! 9
55
fixIO
类似,但它允许您递归IO操作的输出。这就是为什么你的线程被阻止了#34;错误 - 您在没有定义的情况下使用了corecursive结果。
λ fmap (take 10) . fixIO $ \fibs -> putStrLn "computing fibs" >> return (1 : 1 : zipWith (+) fibs (tail fibs))
computing fibs
[1,1,2,3,5,8,13,21,34,55]
答案 1 :(得分:5)
fixIO
是MonadFix IO
实例的见证人。请参阅the HaskellWiki page on MonadFix和论文A Recursive do for Haskell。