The System.IO docs contains a mysterious, undocumented function fixIO
. Its source only adds to the mystery:
fixIO :: (a -> IO a) -> IO a
fixIO
fixIO
is the IO
equivalent of fix.
You've probably seen this definition of the fibonacci sequence:
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
which reuses the fibs
variable within the definition of fibs
to do corecursion. It works because we exploit laziness to define each element of fibs
before it needs to be used.
We can use fix
to do the same without having to define a variable, tying the knot for us:
fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)
Which is handy if you don't especially need to keep the entire fibonacci sequence, you just want to know its tenth element:
λ (fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) !! 9
55
fixIO
is similar, except it lets you recurse on the output of an IO action. That's why you got your "thread blocked" error - you were using the corecursive result without defining it.
λ 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]
fixIO
is the witness to the MonadFix IO instance. See the HaskellWiki page on MonadFix and the paper A Recursive do for Haskell.