2014-07-20 14 views

Odpowiedz

4

Jest to właściwie jednoznaczne z kontekstu.

Zagrajmy w typechecker,

-- From the signature 
MaybeT . return . return :: a -> MaybeT a 
-- From the type of MaybeT 
return . return :: a -> m (Maybe a) 
-- From the type of `.` 
(return :: Maybe a -> m a) . (return :: a -> Maybe a) 

A kiedy mamy typ każdego return, „Algorytm wyboru instancja” będzie poprawnie wybrać pierwszy użył m s return a drugi być Maybe.

+0

Nie powinien być pierwszym zwrotem z ostatniej linii albo typu 'Może a -> m (Może a)' lub bardziej ogólnego 'b -> m b' z' b ~ Może a'? – Laar

+0

@Laar Technicznie tak, ale łatwiej jest (i moralnie równoważne) traktować to w ten sposób. – jozefg

4

Podaje potrzebne typy.

To jasne od znaczenia w instance definicji, że próbujesz określić

returnMaybeT :: Monad m => a -> MaybeT m a 
returnMaybeT x = MaybeT (return (return x)) 

Od MaybeT :: m (Maybe a) -> MaybeT a (rozumianej jako funkcja) Wiemy, że wewnętrzna stos return s musi mieć typ

return (return x) :: Monad m => a -> m (Maybe a) 

teraz wiemy, że return jest polimorficzny funkcja, która ma typ jak

return :: a -> n a 

dla dowolneMonadn. W przypadku tego pierwszego return, ograniczenie Monad m => mówi nam, że m jest i dlatego możemy użyć jego definicji zwrotu. Pozwala nam to uzyskać przez całą drogę w dół do wewnętrznej return

return x :: a -> Maybe a 

a ponieważ wiemy, że Maybe ma instancję Monad możemy użyć return od tego.


Ostatecznie wszystko kompilator musi zrobić, to zredukować jego droga w dół ekspresji próby określenia rodzajów potrzebnych na każdym return. Po określeniu wymaganego typu musi sprawdzić, czy zna instancję Monad dla tego typu. Jest to proste dla Maybe, ponieważ jest konkretne, ale nieco trudniejsze do zobaczenia dla m, ponieważ jest to tylko zmienna.

Powodem m prace dlatego mamy ograniczone zmienną pewnością niektóre typ który instancję Monad.