2015-07-04 17 views
9

Teraz Control.Monad.Error jest przestarzałe, a Control.Monad.Except króluje, wiele źródeł online nie dogoniło i nadal pokazują przykłady użycia Error.Błąd adaptacji z wyjątkiem

Więc jak pójdę o włączaniu

instance Error MyError where 
    noMsg = ... 
    strMsg = ... 

w coś używając Except. Wystarczy zastępując Error z Except nie działa jak Except oczekuje dodatkowe parametry typu

Rozumiem, że dokładnie te same metody nie istnieją w Except, więc jaka jest alternatywa?

Odpowiedz

9

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.

+0

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? –

+0

@ElectricCoffee Rozwinąłem ten bit. –

+1

@ Ø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). –

Powiązane problemy