2010-08-20 13 views
12

Po przeczytaniu (i przejrzeniu niektórych fragmentów) artykułu Wadlera na temat monad, zdecydowałem się dokładniej przeanalizować papier, definiując funktora i instancje aplikacyjne dla każdej opisywanej monady. Korzystanie synonim typuFunktor/instancje aplikacyjne dla stanu w Haskell

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

Wadler używa do określenia monady państwowej, mam następujący (z zastosowaniem podobnych nazw, więc mogę je zdefiniować z deklaracją newtype później).

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) 

Kiedy przełącznik użyciem konstruktora typu w zgłoszeniu newtype np

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

wszystko rozpada. Wszystko to tylko niewielkie modyfikacje, na przykład,

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)) 

jednak nic nie działa w GHC ze względu na fakt, że wyrażenie lambda jest ukryty wewnątrz tego konstruktora typu. Teraz jedynym rozwiązaniem widzę jest zdefiniowanie funkcji:

isntThisAnnoying s (S m) = m s 

w celu związania s do 'St' i faktycznie zwraca wartość, np

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

Czy jest jakiś inny sposób to zrobić który nie korzysta z tych funkcji pomocniczych?

Odpowiedz

11

Jeśli spojrzeć here, widać, że określenie to w ten sposób:

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

tak aby dać wewnętrznej lambda nazwę.

+2

Co oznacza również "runState = flip isntThisAnnoying". – kennytm

+1

Okay - więc mimo że funkcja dodatkowa jest nadal potrzebna, mógłbym tylko zdefiniować typ za pomocą rekordu, pobierając funkcję za darmo. Mówisz więc, że nie ma sposobu na uniknięcie używania funkcji takich jak "runState" lub "run". Dzięki. – danportin

+0

Jeśli boli cię, aby myśleć o nim jako funkcji, pomyśl o tym jako o dostępie strukturalnym. :-) –

4

Najczęstszym sposobem jest zdefiniowanie newtype newtype S a = S {runState : State -> (a, State)}. Wtedy zamiast swojego isntThisAnnoying s (S m) możesz napisać runState t s gdzie t jest taki sam jak S m.
Należy użyć wartości newtype, ponieważ synonimy typów nie mogą być instancjami typu typeclass.

Powiązane problemy