2011-10-10 8 views

Odpowiedz

5

Tak, to jest:

chainl1 p op = foldl (flip ($)) <$> p <*> many (flip <$> op <*> p) 

Chodzi o to, że trzeba przeanalizować p (op p)* i ocenić go jako (...(((p) op p) op p)...).

To może pomóc rozszerzyć definicję trochę:

chainl1 p op = foldl (\x f -> f x) <$> p <*> many ((\f y -> flip f y) <$> op <*> p) 

Jak par op i p są analizowane wyniki są stosowane natychmiast, ale ponieważ p jest prawo operand op, potrzebuje flip.

Tak więc typ wyniku many (flip <$> op <*> p) to f [a -> a]. Ta lista funkcji jest następnie stosowana od lewej do prawej na wartości początkowej p przez foldl.

+0

Czy chcesz wyjaśnić trochę więcej? Dlaczego foldl i flip? – adamse

0

brzydki ale równoważne Applicative definicja:

chainl1 p op = 
    p <**> 
    rest 
    where 
    rest = flip <$> op <*> 
      p <**> 
      pure (.) <*> rest 
     <|> pure id 

Zamiast przejścia po lewej stronie argumentu x wyraźnie do prawej op, op „s to aplikacyjnych formie„łańcuchy”częściowo stosowane do ich prawy- Argument boczny (stąd flip <$> op <*> p) poprzez podniesiony kombinator (.), a następnie zastosowanie najbardziej po lewej p poprzez (<**>) do wynikowego rest :: Alternative f => f (a -> a).

+0

Kiedy próbuję to z 'chainl1 (czytaj <$> wiele cyfrę) ((+) <$ char '+' <|> (*) <$ char '*')' na ' "1 + 2 * 3 + 4"' mam 17 zamiast 13. –

+0

musi 'klapki (.)' zamiast '(.)', to działa ok. –

Powiązane problemy