Krótka odpowiedź brzmi: Wymień Error
za nic w ogóle, należy wymienić ErrorT
przez ExceptT
i rzeczy powinny nadal pracować tak długo, jak nie używać Error
s metody, fail
(które teraz ma inną definicję), aw przypadku jego braku wzorce pasujące w notacji do
.
Zasadnicza różnica pomiędzy systemem starych Control.Monad.Error
oraz nowego systemu Control.Monad.Except
jest to, że nowy system nie narzuca ograniczenie klasy od rodzaju błędu/wyjątku.
Stwierdzono, że możliwość użycia dowolnego typu błędu/wyjątku, polimorficznie, była bardziej przydatna niż nieco zręczna zdolność do dostosowywania konwersji komunikatów o błędach łańcuchowych.
Tak więc klasa Error
po prostu zniknęła.
Jako efekt uboczny, fail
dla ExceptT
jest teraz podnoszona z podstawowej monady. Zmienia to również wpływ uszkodzonych wzorców w notacji do
.
Stara definicja brzmiała:
fail msg = ErrorT $ return (Left (strMsg msg))
co moim zdaniem jest równoważna
fail msg = throwError (strMsg msg)
Jeśli trzeba jeszcze ten problem, można zamiast tego użyć
throwError yourIntendedErrorValue
(throwE
prace zamiast tego, jeśli używasz transformers
(tj. Control.Monad.Trans.Except
) zamiast mtl
.)
Stary do
wzorzec dopasowania awaria miałaby zastosowanie do rzeczy jak
do
Just x <- myErrorTAction
...
gdy działanie rzeczywiście zwraca Nothing
. Jest to bardziej niezręczne, ale możesz np.zastąpić ją wyraźnego case
meczu (zasadniczo desugaring go):
do
y <- myErrorTAction
case y of
Nothing -> throwE ...
Just x -> do
...
@DanielWagner sugeruje następujące czynności, aby uniknąć dodatkowego wcięcia:
do
x <- myErrorTAction >>= maybe (throwError ...) return
...
Usunięcie Error
eliminuje również potrzebę niespójność nazewnictwa to, że Control.Monad.Error
ma: Większość transformatorów stosuje się do zasady, że SomethingT
to nazwa transformatora, a Something
jest aliasem typu dla SomethingT ... Identity
. Stary ErrorT
zepsuł to, ponieważ klasa Error
została użyta do czegoś zupełnie innego.
W nowym systemie, Except e = ExceptT e Identity
, podobnie jak w przypadku innych transformatorów.
Mówisz, że 'fail' działa teraz inaczej, czy możesz podać przykład tego, jak to się stało i jak napisać równoważny kod? –
@ElectricCoffee Rozwinąłem ten bit. –
@ ØrjanJohansen Inny wzór, którego używałem od czasu do czasu: 'do {y <- myErrorTAction >> = może (throwError ...) return; ...} '. Unika konieczności dodawania wcięcia i może być dostosowany do innych dopasowań wzorców; na przykład 'do {y_ <- myErrorTAction; y <- case y_ of {Nothing -> throwError ...; Tylko v -> return v}; ...} 'który dodaje warstwę wcięcia, ale tylko tymczasowo (tj. nie wymagałoby zagnieżdżonego wcięcia, jeśli chcesz wykonać dwa dopasowania do wzorca). –