2015-01-04 13 views
8

Sono un principiante di Haskell molto nuovo. Ho un espressione di lavoro:Equivalenti di espressione Haskell

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

che sembra funzionare perfettamente (sto usando il pacchetto Parsec, ma spero che questa domanda non ha nulla a che fare con la sua funzionalità, per quanto ne so <|> è un Parsec- definito operatore infisso). parseA e parseB hanno entrambi il tipo monad Parser Foo, così come l'intera espressione.

In base a quello che ho letto finora, sembra che questo dovrebbe essere equivalente a

do return (try parseA <|> parseB) 

e

do return $ try parseA <|> parseB 

ma nessuno di questi ultimi di compilazione, si lamentano di tipi non corrispondenti (errori sotto).

Il mio altro tentativo di riscrivere questo, come

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

sembra funzionare. Ma se ho frainteso anche questo, per favore dì.

Quindi la mia domanda è: qualcuno può spiegare perché i primi tre sono diversi. Sono confuso perché non sono equivalenti. Cosa mi manca?


errori (nel caso in cui questo è rilevante, anche se FWIW non sto cercando di 'risolvere' il mio codice - ho una versione funzionante, sto cercando di capire come le versioni differiscono):

do return (try parseA <|> parseB) 

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

e

do return $ try parseA <|> parseB 

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) 

risposta

11

Do Notation Dezuccheraggio

Il rules for do notation desugaring implica che

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

è equivalente a

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

($) contro (>>=)

Dal è una versione capovolta di (>>=), entrambi sono equivalenti a

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

Questo implica che l'unica differenza tra la versione corretta e return $ try parseA <|> parse B è la differenza tra e ($), i cui tipi sono:

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

Si può vedere che ($) non è un sostituto per , ma forse si può anche vedere che sono in qualche modo simili. Un modo di vedere le cose è che – e quindi anche (>>=) – è un tipo di applicazione funzione che applica "funzioni monadici" di tipo a -> m b per qualche Monade m a "valori monadici" di tipo m a per qualche Monade m, considerando ($) è il solito tipo di applicazione di funzione che applica le funzioni di tipo a -> b a valori di tipo a.

leggi Monade

Uno dei monad laws è che

k >>= return = k 

Ciò implica che

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

può anche essere scritta come

try parseA <|> parse B 

che significa Anche la forma originale usando la notazione può essere scritta in questo modo.

+4

Grazie, questo era il consiglio che dovevo capire. L'altro bit che mi mancava è che <- non è solo un compito, toglie la Monade e restituisce il tipo sottostante, quindi x <- y allora foo x non è equivalente a foo y.Apprezzo la risposta completa, Rein. – Ian