2009-06-03 11 views
6

Mam funkcję, która sprawdza, czy dany typ jest podtypem innego typu:Obsługa błędów w Haskell albo monady

st :: Monad m => Map String Type -- ^type environment 
    -> Set (Type, Type) -- ^assumed subtypes 
    -> (Type, Type) -- ^we are checking if lhs <: rhs  
    -> m (Set (Type, Type)) 

chcę zrobić obsługę błędów. Mam następującą definicję:

instance Monad (Either String) where 
    return v = Right v 
    fail s = Left s 
    (Left s) >>= _ = Left s 
    (Right v) >>= f = f v 

Czasami mogę zrobić obsługę błędów traktując wynik st jako Either. Na przykład, poniższa funkcja działa i pobiera mi wiadomości, które wynikają z wywoływania „fail” wewnątrz St:

isSubType env cs t1 t2 = result where 
    result = case st env (S.empty) (t1, t2) of 
    Left msg -> Left msg 
    Right rel -> Right() 

Teraz jestem wewnątrz st i chcę rekursywnie nazwać. Z jakiegoś powodu, poniższy kod, zagnieżdżona głęboko w St:

let do_t1 rel t1 = case st env rel (t1, t2) of 
     Left msg -> fail $ printf "type %s in the union is not a subtype\ 
          \ of the rhs, %s, because: %s" (renderType t1) 
          (renderType t2) (show msg) 
     Right rel -> return rel 

Nie typ kontroli, ale daje mi następujący błąd:

No instance for (Monad (Either t)) 
     arising from a use of `st' 
        at src/TypedJavaScript/Types.hs:386:24-42 
    Possible fix: add an instance declaration for (Monad (Either t)) 

Dlaczego traktując wynik st albo jako praca poza "st", ale nie w środku? Jak mogę zmienić mój kod tak, aby działał w środku?

+3

Wygląda na to, że ponownie wdrażasz [Control.Monad.Error] (http://www.haskell.org/ghc/docs/latest/html/libraries/mtl/Control-Monad-Error.html)? – ephemient

Odpowiedz

5

Myślę, że problemem jest to, że dzwonisz pod numer show msg, gdzie powinieneś po prostu użyć msg. W rezultacie kompilator nie może wydedukować, że miałeś na myśli Either String; wszystko, co wie, to, że masz Either t, gdzie spełnione jest ograniczenie Show t. Zastąpienie show msg z msg powinno to naprawić.