2013-02-27 10 views
18

OK, więc wiem, co zawiera klasa typu Applicative i dlaczego jest to przydatne. Ale nie jestem w stanie opisać, w jaki sposób używałbyś tego w nie nietrywialnym przykładzie.Tłumaczenie z monada na aplikacyjny

Rozważmy na przykład następujący dość prosty parsec parsera:

integer :: Parser Integer 
integer = do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 

Teraz jak do cholery chcesz napisać, że bez użycia instancji Monad dla Parser? Wiele osób twierdzi, że można to zrobić i jest to dobry pomysł, ale nie wiem, jak dokładnie.

Odpowiedz

11
integer :: Parser Integer 
integer = read <$> (many1 space *> many1 digit) 

Albo

integer = const read <$> many1 space <*> many1 digit 

Czy uważasz, albo z nich są bardziej czytelne jest do ciebie.

+0

Dlaczego "const"? – MathematicalOrchid

+1

Chcemy zignorować wartość (ale nie efekt) 'many1 space' i zastosować' read' do wartości 'wiele1 cyfr'. (Przepraszam, właśnie wszedłem, jest późno, jestem zmęczony: gram szybko i luźno z terminologią.) Jeśli sobie wyobrazisz, że 's' i' d' reprezentują wartości 'many1 space' i' many1 digit', następnie wartość (ignorowanie efektów) 'const read <$> many1 space <*> many1 digit' to' const read sd' = 'read d'. – dave4420

38

bym napisać

integer :: Parser Integer 
integer = read <$ many1 space <*> many1 digit 

Jest grono wiązanie lewe (jak aplikacji) Operatorzy parser-budowlanych <$>, <*>, <$, <*. Rzecz po lewej stronie powinna być czystą funkcją, która składa wartość wyniku z wartości składowych. Rzecz po prawej stronie każdego operatora powinna być parserem, zbiorowo podając elementy gramatyki od lewej do prawej. Wybór operatora zależy od dwóch opcji, jak następuje.

the thing to the right is signal/noise 
    _________________________    
    the thing to the left is \   
          +------------------- 
        pure/| <$>  <$ 
        a parser | <*>  <* 

Tak, wybrawszy read :: String -> Integer jako czystej funkcji, która ma zamiar dostarczyć semantykę parsera, możemy sklasyfikować główną przestrzeń jako „szum”, a bandą cyfr jako „sygnał”, stąd

read <$ many1 space <*> many1 digit 
(..) (.........)  (.........) 
pure noise parser  | 
(.................)  | 
    parser    signal parser 
(.................................) 
        parser 

można łączyć wiele możliwości z

p1 <|> ... <|> pn 

i wyraźnej niemożności z

empty 

Rzadko trzeba nazwać komponenty w analizatorach składni, a wynikowy kod wygląda bardziej jak gramatyka z dodaną semantyką.

+8

Wow, wiedziałem o '<$', ale użyłem go tylko wtedy, gdy rzecz po lewej stronie była stała, a prawo było prostą wartością ... Nigdy nie myślałem o tym, co by się stało, gdybym umieścił funkcję po lewej: P Nice trick –

7

Twój przykład można stopniowo przepisany do postaci, która wyraźniej przypomina aplikacyjnych:

do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 
  1. definicji do notacji:

    many1 space >> (many1 digit >>= \ds -> return $ read ds) 
    
  2. definicja $:

    many1 space >> (many1 digit >>= \ds -> return (read ds)) 
    
  3. definicja .:

    many1 space >> (many1 digit >>= (return . read)) 
    
  4. prawo 3-te monada (asocjatywność):

    (many1 space >> many1 digit) >>= (return . read) 
    
  5. definicja liftM (w nie- do notacji):

    liftM read (many1 space >> many1 digit) 
    

To jest (lub powinno być, jeśli nie zawiodłem :)) identyczne zachowanie do twojego przykładu.

Teraz, jeśli zastąpić liftM z fmap z <$> i >> z *>, ty dostać aplikacyjnych:

read <$> (many1 space *> many1 digit) 

Jest to ważne, ponieważ liftM, fmap i <$> są generalnie ma być synonimami, jak są >> i .

To wszystko działa i możemy to zrobić, ponieważ oryginalny przykład nie użył wyniku żadnego parsera do zbudowania następującego parsera.

+0

Cool! Innym sposobem na napisanie 'przeczytaj <$ many1 space <*> many1 digit'. :) Ostatnie zdanie jest bardzo ważne. Czy to oznacza, że ​​ten styl odpowiada gramatom bezkontekstowym, a bardziej ogólne gramatyki muszą być przetwarzane w stylu monadycznym? –

+0

@WillNess Nie jestem ekspertem w tej dziedzinie, ale wierzę, że tak jest. –