Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does fixIO do?

Tags:

haskell

The System.IO docs contains a mysterious, undocumented function fixIO. Its source only adds to the mystery:

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

This appears to do the moral equivalent of dereferencing NULL (reading from an empty MVar). Indeed, trying it:

import System.IO
main = fixIO $ \x -> putStrLn x >> return x

results in an error "thread blocked indefinitely in an MVar operation"

Searching turns up nothing save a 15 year old message from Simon Peyton-Jones himself, in which he provides the above source, and hopes that it would make the meaning clear (and yet here I am).

Can someone please shed some light on this? What does fixIO do and when should I use it?

like image 817
ridiculous_fish Avatar asked Sep 16 '14 18:09

ridiculous_fish


2 Answers

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]
like image 196
rampion Avatar answered Sep 22 '22 23:09

rampion


fixIO is the witness to the MonadFix IO instance. See the HaskellWiki page on MonadFix and the paper A Recursive do for Haskell.

like image 25
luqui Avatar answered Sep 18 '22 23:09

luqui