2010-08-20 7 views
12

Nachdem ich Wadlers Aufsatz über Monaden gelesen und einige Abschnitte über Monaden gelesen hatte, beschloss ich, die Arbeit genauer zu durcharbeiten, indem ich Funktoren und anwendbare Instanzen für jede der beschriebenen Monaden definierte. Unter Verwendung des Typs SynonymFunctor/Applicative Instanzen für Staat in Haskell

type M a = State -> (a, State) 
type State = Int 

Wadler verwendet den Zustand monadisch zu definieren, I haben die folgenden (mit einem damit verbundenen Namen, damit ich sie mit einer newtype Erklärung definieren später).

fmap' :: (a -> b) -> M a -> M b 
fmap' f m = \st -> let (a, s) = m st in (f a, s) 

pure' :: a -> M a 
pure' a = \st -> (a, st) 

(<@>) :: M (a -> b) -> M a -> M b 
sf <@> sv = \st -> let (f, st1) = sf st 
         (a, st2) = sv st1 
        in (f a, st2) 

return' :: a -> M a 
return' a = pure' a 

bind :: M a -> (a -> M b) -> M b 
m `bind` f = \st -> let (a, st1) = m st 
         (b, st2) = f a st1 
        in (b, st2) 

Wenn ich Schalter einen Typkonstruktor in einer newtype Erklärung unter Verwendung beispielsweise

newtype S a = S (State -> (a, State)) 

alles fällt auseinander. Alles ist nur eine leichte Modifikation, zum Beispiel,

instance Functor S where 
fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s)) 

instance Applicative S where 
pure a = S (\st -> (a, st)) 

jedoch nichts in GHC läuft aufgrund der Tatsache, dass der Lambda-Ausdruck in diesem Typkonstruktor verborgen ist. Nun ist die einzige Lösung, die ich sehe, ist eine Funktion zu definieren:

isntThisAnnoying s (S m) = m s 

um s ‚st‘ zu binden und tatsächlich einen Wert zurückgeben, zB

fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s)) 

Gibt es eine andere Möglichkeit, dies zu tun das verwendet diese Hilfsfunktionen nicht?

Antwort

11

Wenn Sie here anschauen, werden Sie sehen, dass sie es auf diese Weise zu definieren:

newtype State s a = State { runState :: (s -> (a,s)) } 

, um die innere Lambda einen Namen zu geben.

+2

Das bedeutet auch 'runState = flip isntThisAnnoying'. – kennytm

+1

Okay - während eine Hilfsfunktion noch benötigt wird, könnte ich einfach den Typ mit einem Datensatz definieren, um die Funktion kostenlos zu bekommen. Was Sie sagen, ist, dass es keine Möglichkeit gibt, Funktionen wie 'runState' oder 'run' zu vermeiden. Vielen Dank. – danportin

+0

Wenn es Ihnen weh tut, es als eine Funktion zu betrachten, denken Sie stattdessen an einen Struct Field Accessor. :-) –

4

Der übliche Weg ist newtype newtype S a = S {runState : State -> (a, State)} zu definieren. Dann können Sie statt isntThisAnnoying s (S m)runState t s schreiben, wobei t dasselbe ist wie S m.
Sie müssen eine newtype verwenden, weil Typ Synonyme nicht Typklasseninstanzen sein können.