fixIO做什么?

时间:2014-09-16 18:32:48

标签: haskell

System.IO docs包含一个神秘的,未记录的函数fixIOIts 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做什么以及何时应该使用它?

2 个答案:

答案 0 :(得分:12)

fixIOIO相当于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)

fixIOMonadFix IO实例的见证人。请参阅the HaskellWiki page on MonadFix和论文A Recursive do for Haskell