2017-01-22 53 views
5

Jak przekonwertować StateT g (Either E) T na ExceptT E (StateT g Identity) T?Zamień monady wewnętrzne i zewnętrzne

Może się przydać tutaj mieszanka traverse i hoist.

+2

Gdy 'StateT g (Eise) t' nie powiedzie się, nie zapewnia żadnego stanu. Co powinien robić odpowiedni "Wyjątek e (StateT g Tożsamość)"? – danidiaz

+0

Nie mogę przypomnieć sobie dokładnych definicji, ale czy pierwsza monada nie może się zepsuć w zależności od stanu (np. Czy stan jest liczbą parzystą), kiedy druga nie może? – chi

Odpowiedz

9

You can't exchange an arbitrary pair of monads. Ale możesz wymienić te dwie szczególne monady. Najłatwiej zrozumieć, jeśli rozszerzysz newtype s w definicjach tych transformatorów monad.

Biorąc

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

i

newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) } 

rozszerzenie newtype S w pierwszej typu wypowiedzi daje nam izomorfizm

StateT s (Either e) a <-> s -> Either e (s, a) 

natomiast dla drugiego otrzymujemy

ExceptT e (StateT s Identity) a <-> s -> (s, Either e a) 

Należy pamiętać, że Either e (s, a) może lub nie może zawierać wartości s, natomiast (s, Either e a) zawsze. Teraz można przejść od tego ostatniego do pierwszego, po prostu przez traverse w kodzie w funkcji, ale przejście w drugą stronę wymaga pewnego rozumowania specyficznego dla dziedziny: jeśli obliczenie zgłasza błąd, powinniśmy skierować stan przez niezmieniony do łapacza błędu. (Czy jest to słuszne? Uważam, że jest to raczej dyskusyjne.)

stateTEitherToExceptTState :: (s -> Either e (s, a)) -> (s -> (s, Either e a)) 
stateTEitherToExceptTState f s = 
    case f s of 
     Left e -> (s, Left e) 
     Right sa -> fmap Right sa 
+1

Myślę, że 'stateTEitherToExceptTState' nie jest poprawnym morfizmem monady. Jeśli 'm' jest akcją, która nie zawodzi, oraz' f' strzałką Kleisli, która zawsze zawodzi, 'morph (m >> = f)' nie jest równe 'morph m> = morph. f'. – danidiaz