2014-09-16 5 views
13

Le System.IO docs contient une fonction mystérieuse non documentée fixIO. Its source ne fait qu'ajouter au mystère:Que fait le fixIO?

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

Cela semble faire l'équivalent moral de déréférencement NULL (lecture d'un MVar vide). En effet, l'essayer:

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

provoque une erreur « thread bloqué indéfiniment dans une opération MVar »

Recherche se présente rien sauver un 15 year old message de Simon Peyton-Jones lui-même, dans lequel il fournit la source ci-dessus et espère que cela clarifiera le sens (et pourtant je suis ici).

Quelqu'un peut-il faire la lumière sur ce sujet? Qu'est-ce que fixIO fait et quand devrais-je l'utiliser?

Répondre

11

fixIO est l'équivalent IO de fix.

Vous avez probablement vu cette définition de la séquence de fibonacci:

fibs = 1 : 1 : zipWith (+) fibs (tail fibs) 

qui réutilise la variable fibs dans la définition de fibs faire corecursion. Cela fonctionne parce que nous exploitons la paresse pour définir chaque élément de fibs avant qu'il ne soit utilisé.

Nous pouvons utiliser fix faire la même chose sans avoir à définir une variable, tying the knot pour nous:

fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs) 

Ce qui est pratique si vous n'avez pas besoin surtout de garder la séquence entière de fibonacci, vous voulez juste connaître son dixième élément:

λ (fix $ \fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) !! 9 
55 

fixIO est similaire, sauf qu'il vous permet de rECURSE sur la sortie d'une action IO. C'est pourquoi vous avez eu votre erreur "thread bloqué" - vous utilisiez le résultat corécursif sans le définir. `Fix` n'a rien à voir avec le fait de ne pas garder autour de la séquence entière de fibonacci

λ 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] 
+0

'laissez fibs = 1: 1: zipWith (+) fibs (fibs de la queue) dans les fibs !! 9' fera aussi bien. –

+0

Tom Ellis: Je suis sur mon téléphone mais je crois que la définition du correctif est 'fix f = let a = f a dans a', donc vous avez raison, ce n'est pas nécessaire. mais c'est équivalent. – rampion

+0

Il peut aussi être plus succint: 'fix (1:)' est plus court que 'let x = 1: x dans x'. – rampion