2015-01-04 18 views
8

Jestem bardzo nowym uczniem Haskella. Mam wyraz robocza:Równoważniki ekspresji Haskella

do x <- try parseA <|> parseB 
    return x 

który wydaje się doskonale działa (używam pakiet Parsec, ale mam nadzieję, że kwestia ta nie ma nic wspólnego z jego funkcjonalności, o ile wiem, <|> jest Parsec- zdefiniowany operator infiksów). parseA i parseB oba mają monadę typu Parser Foo, podobnie jak całe wyrażenie.

Na podstawie tego, co już do tej pory przeczytać, wydaje się to powinno być równoważne

do return (try parseA <|> parseB) 

i

do return $ try parseA <|> parseB 

ale żaden z drugiej kompilacji, ale skarżą się na niedopasowane typów (błędów poniżej).

Moja druga próba przerobienia tego, jak

(try parseA <|> parse B) >>= return 

wydaje się działać. Ale jeśli źle to zrozumiałem, proszę powiedz.

Moje pytanie brzmi, czy ktoś może wyjaśnić, dlaczego pierwsze trzy są różne. Jestem zdezorientowany, dlaczego nie są one równoważne. czego mi brakuje?


Błędy (w przypadku, gdy jest to właściwe, choć FWIW Nie szukam, aby „naprawić” mój kod - Mam wersję pracy, szukam, aby zrozumieć, w jaki sposób różne wersje):

do return (try parseA <|> parseB) 

daje

parse.hs:76:11: 
    Couldn't match expected type ‘Foo’ 
       with actual type ‘Text.Parsec.Prim.ParsecT 
            [Char]() Data.Functor.Identity.Identity Foo’ 

i

do return $ try parseA <|> parseB 

daje

parse.hs:76:3: 
    Couldn't match type ‘Text.Parsec.Prim.ParsecT 
          [Char]() Data.Functor.Identity.Identity Foo’ 
        with ‘Foo’ 
    Expected type: Parser Foo 
     Actual type: Text.Parsec.Prim.ParsecT 
        String 
        () 
        Data.Functor.Identity.Identity 
        (Text.Parsec.Prim.ParsecT 
         [Char]() Data.Functor.Identity.Identity Foo) 

Odpowiedz

11

Do Notation Desugaring

rules for do notation desugaring oznacza, że ​​

do x <- try parseA <|> parseB 
    return x 

jest równoważna

(try parseA <|> parse B) >>= return 

($) kontra (>>=)

Od jest odwrócona wersja (>>=), oba są równoważne

return =<< (try parseA <|> parse B) 

Oznacza to, że jedyna różnica między poprawnej wersji i return $ try parseA <|> parse B jest różnica między i ($), których typy:

($) :: (a -> b) -> a -> b 
(=<<) :: (a -> m b) -> m a -> m b 

Możesz zobaczyć, że ($) nie jest zamiennikiem dla , ale być może również zauważysz, że są one nieco podobne. Jednym ze sposobów, aby spojrzeć na to jest fakt, że – a więc także (>>=) – jest rodzajem zastosowania funkcji, które dotyczy „monadycznego funkcje” typu a -> m b jakiegoś Monady m do „wartości monadycznego” typu m a jakiegoś Monady m, natomiast ($) jest typowy rodzaj aplikacji funkcji, która stosuje funkcje typu a -> b do wartości typu a.

Monad U.

Jednym z monad laws że

k >>= return = k 

Oznacza to, że

(try parseA <|> parse B) >>= return 

można również zapisać jako

try parseA <|> parse B 

co oznacza, że r Oryginalna forma z użyciem notacji również może być napisana w ten sposób.

+4

Dziękuję, to była wskazówka, którą musiałem zrozumieć. Innym bitem, którego mi brakowało, jest to, że <- to nie tylko zadanie, to usuwa Monadę i zwraca typ bazowy, więc x <- y następnie foo x nie jest równoważne foo y.Doceniam kompleksową odpowiedź, Rein. – Ian