fixIO做什么?

rid*_*ish 16 haskell

System.IO文档包含一个神秘的,未公开的函数fixIO.它的来源只会增加神秘感:

fixIO :: (a -> IO a) -> IO a
fixIO k = do
    m <- newEmptyMVar
    ans <- unsafeInterleaveIO (takeMVar m)
    result <- k ans
    putMVar m result
    return result
Run Code Online (Sandbox Code Playgroud)

这似乎与取消引用NULL(从空的MVar读取)相当.确实,尝试一下:

import System.IO
main = fixIO $ \x -> putStrLn x >> return x
Run Code Online (Sandbox Code Playgroud)

导致错误"线程在MVar操作中无限期地被阻塞"

除了Simon Peyton-Jones本人提供的15年前的消息之外,搜索没有任何结果,他提供了上述来源,并希望它能使意义明确(而且我在这里).

有人可以对此有所了解吗?fixIO做什么以及何时应该使用它?

ram*_*ion 12

fixIOIO的等效fix.

您可能已经看到了斐波那契序列的这个定义:

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)

它重用了fibs定义中的变量fibs来进行核心化.它的工作原理是因为我们利用懒惰来定义fibs需要使用之前的每个元素.

我们可以使用fix它来做同样的事情,而不必定义一个变量,为我们打结:

fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)

如果你不特别需要保留整个斐波那契序列,这是很方便的,你只想知道它的第十个元素:

? (fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) !! 9
55
Run Code Online (Sandbox Code Playgroud)

fixIO类似,但它允许你递归IO动作的输出.这就是为什么你得到了"线程阻塞"错误 - 你在没有定义它的情况下使用了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]
Run Code Online (Sandbox Code Playgroud)

  • 请注意,根据紧缩法律,它只执行一次monadic动作:http://stackoverflow.com/questions/25814489/is-there-an-instance-of-monad-but-not-of-monadfix (2认同)