2014-09-12 16 views
13

Die Frage ist meist im Titel. Es scheint, wie mfix kann für jede monadischen Berechnung definiert werden, auch wenn sie auseinandergehen könnte:Gibt es eine Instanz von Monad, aber nicht von MonadFix?

mfix :: (a -> m a) -> m a 
mfix f = fix (join . liftM f) 

Was ist mit dieser Konstruktion ist falsch? Warum sind die Klassen Monad und MonadFix getrennt (d. H. Welcher Typ hat eine Instanz von Monad, aber nicht von MonadFix)?

+3

Die Fortsetzungs-Monade hat nicht den gewünschten Fixpunktoperator. – augustss

+1

Siehe auch [Warum kann es keine Instanz von MonadFix für die Continuation-Monade geben?] (Http://stackoverflow.com/q/25827227/1333025). –

Antwort

16

Die left shrinking (or tightening) law says dass

mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y) 

Insbesondere bedeutet dies, dass

mfix (\x -> a' >> f x) = a' >> mfix f 

was bedeutet, daß die monadische Aktion innerhalb mfix muss genau einmal ausgewertet werden. Dies ist eine der Haupteigenschaften von MonadFix, die Ihre Version nicht erfüllen kann.

dieses Beispiel betrachten, die eine zyklische wandelbar Liste erstellt (lassen Sie uns die Tatsache außer Acht lassen, dass Sie tun können, dass ohne mfix dank Veränderlichkeit):

import Control.Monad 
import Control.Monad.Fix 
import Data.IORef 

data MList a = Nil | Cons a (IORef (MList a)) 

mrepeat :: a -> IO (MList a) 
mrepeat x = mfix (liftM (Cons x) . newIORef) 

main = do 
    (Cons x _) <- mrepeat 1 
    print x 

Mit Ihrer Variante mfix der Anruf an mrepeat nie beendet, als Du rufst den inneren Teil mit newIORef auf unbestimmte Zeit an.

6

Ihre Definition von mfix kann nicht garantiert werden, dass sie der Standard entspricht. In der Tat, zumindest in der Liste monadisch ist es schärfere:

> take 1 $ mfix (\x -> [1,x]) 
[1] 
> let mfix2 :: Monad m => (a -> m a) -> m a; mfix2 f = fix (join . liftM f) 
> take 1 $ mfix2 (\x -> [1,x]) 
Interrupted. 
Verwandte Themen