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?
Co oznacza również "runState = flip isntThisAnnoying". – kennytm
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
Jeśli boli cię, aby myśleć o nim jako funkcji, pomyśl o tym jako o dostępie strukturalnym. :-) –