2017-09-07 10 views

Odpowiedz

6

Po rozwinięciu nowych typów, mamy join :: Monad m => m (Maybe (m (Maybe a))) -> m (Maybe a) w pierwszym przypadku i join :: Monad m => Maybe (m (Maybe (m a))) -> Maybe (m a) w drugim.

realizację pierwszego join potrzebny jest sposób na dystrybucję Maybe nad m: dist1 :: Monad m => Maybe (m a) -> m (Maybe a):

join1 :: m (Maybe (m (Maybe a))) -> m (Maybe a) 
join1 = fmap join . join . fmap dist1 

Aby wdrożyć drugi join trzeba przeciwny prawo dystrybucyjny dist2 :: Monad m => m (Maybe a) -> Maybe (m a)

join2 :: Maybe (m (Maybe (m a))) -> Maybe (m a) 
join2 = fmap join . join . fmap dist2 

dist1 jest łatwe zaimplementować (odejdę, udowadniając ci prawa transformatora Monada):

dist2 nie jest takie proste. Nie można tego zrobić dla arbitralnego Monad. Jako kontrprzykład, niech odebrać m być „czytnik” monada (->) r:

dist2 :: (r -> Maybe a) -> Maybe (r -> a) 

Skoro nie masz dostępu do r, jedyną realizację dist2 że będziemy typecheck jest const Nothing, który pewnie wygrał” t spełniają prawa monad.

+1

Myślę, że łatwiej jest dostrzec problem, skupiając się bezpośrednio na 'join2', niż próbować zbyt głęboko dyskutować, w jaki sposób musi on się rozpaść. Możemy dopasować wzorzec do argumentu, a następnie potrzebujemy 'm (Maybe (m a)) -> Maybe (m a)'. Jedynym nietrywialnym wyborem jest 'Just', który prowadzi do' m (Maybe (m a)) -> m a', który pachnie jak kłopot. – dfeuer

2

Patrząc na StateT może być pouczające:

newtype StateT s m a = StateT { runStateT :: s -> m (a,s) } 

Tutaj państwo nie jest ani „wewnętrzny”, ani „zewnętrzny”, ale jego typ jest przeplatany z monady jest transformujące, niektóre bity w środku, jakiś zewnątrz. I rzeczywiście:

newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a } 

jest "zewnętrzna". To zależy od tego, jaki to transformator. Prawdopodobnie istnieje pewna teoria kategorii, która przynajmniej częściowo wyjaśnia to przeplatanie, jestem ciekawy o tym (inteligencja?).

kontrastowy z aplikacyjnych funktorów, na którym

newtype Compose f g a = Compose { getCompose :: f (g a) } 

jest aplikacyjne, tak więc, nie zawsze jest jasny „wewnętrzny zewnętrzną /” związek. Można zrób aplikacyjnych tylko StateT, a znalezienie jej strukturę przez Compose (State s):

ApplicativeStateT s f a = s -> (s, f a) 

W rzeczywistości, istnieje jeszcze jeden, jeśli komponować z prawej strony:

ApplicativeStateT' s f a = f (s -> (s,a)) 

Ale monady nie mają takiej prawidłowości.

+1

Podejrzewam, że nazwy, które podajemy niektóre transformatory, mogą sugerować fałszywy wzór. Nazwamy 'StateT' po' State' i 'ReaderT' po' Reader', etc, co wydaje się sugerować relację jeden-do-jednego. Ale monady i transformatory Monady są całkiem inne, o czym świadczą różne rzeczy, które twierdzą, że są "poprawnym" monadowym transformatorem. "' ListT' done right ", pipe/conduit/streaming/machines/coroutines oraz' LogicT' (i wersja "LogicT" bez refleksji) wydają się mieć uzasadnione roszczenia do tytułu. – dfeuer