2013-03-15 9 views
7

Ok, ich habe so herausgefunden, wie Reader zu implementieren (und ReaderT, nicht gezeigt), um das operational Paket mit:Wie implementiere ich Reader mit freien Monaden?

{-# LANGUAGE GADTs, ScopedTypeVariables #-} 

import Control.Monad.Operational 

data ReaderI r a where 
    Ask :: ReaderI r r 

type Reader r a = Program (ReaderI r) a 

ask :: Reader r r 
ask = singleton Ask 

runReader :: forall r a. Reader r a -> r -> a 
runReader = interpretWithMonad evalI 
    where evalI :: forall b. ReaderI r b -> (r -> b) 
      evalI Ask = id 

Aber ich kann mein Leben nicht vorstellen, wie dies mit freiem Monaden zu tun (Ich benutze Edward Kmetts free Paket). Der nächstgelegene ich bekommen habe ist das, was ich verstehe, ist Betrug (etwas darüber, wie ((->) r) ist bereits eine Monade):

import Control.Monad.Free 

type Reader r a = Free ((->) r) a 

ask :: Reader r r 
ask = Free Pure 

runReader :: Reader r a -> r -> a 
runReader (Pure a) _ = a 
runReader (Free k) r = runReader (k r) r 

-- Or, more simply and tellingly: 
-- 
-- > runReader = retract 

Selbst wenn dies nicht so dumm war, wie ich vermute, es ist, es ist nicht das, was ich will, denn was ich will, ist grundsätzlich in der Lage, eine Reader als Daten zu prüfen ...

+1

Ich glaube nicht, dass es ohne einen Funktionstyp irgendwo getan werden kann. –

Antwort

3

Ich glaube nicht, dass es getan werden kann, außer sie, wie Sie haben. Aber ich denke nicht, dass dies für den Leser einzigartig ist. Betrachten Sie die kostenlose Monade Version des Schriftstellers

data WriterF m a = WriterF m a deriving (Functor) 

type Writer m = Free (WriterF m) 

offensichtlich ist WriterF isomorph Schriftsteller, aber das macht die Art und Weise verhalten wir uns mit der einfachen Algebra

algebraWriter :: Monoid m => WriterF m (m,a) -> (m,a) 
algebraWriter (WriterF m1 (m2,a)) = (m1 <> m2,a) 

so

runWriter :: Monoid m => Writer m a -> (m,a) 
runWriter (Pure a) = (mempty,a) 
runWriter (Free x) = algebraWriter . fmap runWriter $ x 

erwarten Ebenso denke ich an den Free Reader als

type ReaderF r = (->) r 

type Reader r = Free (ReaderF r) 

Ich mag das, weil das Hinzufügen sie Sie den Zustand Monade

type State x = Free ((ReaderF x) :+: (WriterF x)) 

runState :: State x a -> x -> (a,x) 
runState (Pure a) x     = (a,x) 
runState (Free (Inl f)) x    = runState (f x) x 
runState (Free (Inr (WriterF x f))) _ = runState f x 

Hinweis gibt, dass Ihre Betriebs Lösung mit Free die „freie Funktors“ arbeiten gemacht werden könnten, indem als kann alles, was mit operativen funktioniert

data FreeFunctor f x = forall a. FreeFunctor (f a) (a -> x) 

aber ist, dass FreeFunctor ReaderI-(->) auch isomorph.

1

Nun, ich habe das jetzt seit 3 ​​Stunden angeschaut, und ich glaube, ich habe etwas gefunden, das mir besser gefällt. Da die Reader applicative die gleiche wie die Reader Monade ist, können wir eine applicative Version von operational versuchen:

{-# LANGUAGE RankNTypes, GADTs, FlexibleInstances #-} 

import Control.Applicative 

data ProgramA instr a where 
    Pure :: a -> ProgramA r a 
    Ap :: ProgramA r (a -> b) -> ProgramA r a -> ProgramA r b 
    Instr :: instr a -> ProgramA instr a 

infixl `Ap` 

instance Functor (ProgramA instr) where 
    fmap f (Pure a) = Pure (f a) 
    fmap f (ff `Ap` fa) = ((f .) <$> ff) `Ap` fa 
    fmap f instr = Pure f `Ap` instr 

instance Applicative (ProgramA instr) where 
    pure = Pure 
    (<*>) = Ap 

interpretA :: Applicative f => 
       (forall a. instr a -> f a) 
      -> ProgramA instr a 
      -> f a 
interpretA evalI (Pure a) = pure a 
interpretA evalI (ff `Ap` fa) = interpretA evalI ff <*> interpretA evalI fa 
interpretA evalI (Instr i) = evalI i 

data ReaderI r a where 
    Ask :: ReaderI r r 

type Reader r a = ProgramA (ReaderI r) a 

ask :: Reader r r 
ask = Instr Ask 

runReader :: Reader r a -> r -> a 
runReader = interpretA (\Ask -> id) 

instance Monad (ProgramA (ReaderI r)) where 
    return = pure 
    ma >>= f = runReader <$> fmap f ma <*> ask 

Die Struktur eines ProgramA (ReaderI r) a) kann mehr als entweder Program (ReaderI r) a oder Free ((->) r) a ohne weiteres überprüft werden.

Verwandte Themen