2013-02-27 5 views
18

ОК, поэтому я знаю, что класс класса Applicative содержит, и почему это полезно. Но я не могу полностью заткнуть мозг вокруг того, как вы будете использовать его в нетривиальном примере.Перевести с монады на аппликацию

Рассмотрим, например, следующий довольно простой Parsec парсер:

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

Теперь, как чёрта вы пишете, что без использования экземпляра Monad для Parser? Многие люди утверждают, что это можно сделать и это хорошая идея, но я не могу понять, как именно.

ответ

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

Или

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

ли вы думаете, либо из них более читаемым до вас.

+0

Почему 'const'? – MathematicalOrchid

+1

Мы хотим игнорировать значение (но не эффект) 'many1 space' и применять' read' к значению 'many1 digit'. (Извините, я только что пришел, уже поздно, я устал: я играю быстро и свободно с терминологией.) Если вы представляете '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' many1 digit' соответственно, тогда значение (игнорируя эффекты) 'const read <$> many1 space <*> many1 digit' is' const read sd' = 'read d'. – dave4420

38

Я бы написать

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

Там куча левого ассоциативно (например, приложения) парсер-строительные операторы <$>, <*>, <$, <*. Вещью в крайнем левом углу должна быть чистая функция, которая собирает значение результата из значений компонента. Вещь справа от каждого оператора должна быть парсером, в совокупности предоставляющим компоненты грамматики слева направо. Какой оператор использовать, зависит от двух вариантов:

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

Таким образом, избрав read :: String -> Integer как чистая функция, которая собирается доставить семантику парсера, мы можем классифицировать ведущее место как «шум» и кучей цифр, как «сигнал», следовательно,

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

Вы можете объединить несколько возможностей с

p1 <|> ... <|> pn 

и выражают невозможность с

empty 

Редко необходимо назвать компоненты в синтаксических анализаторах, а полученный код больше похож на грамматику с добавленной семантикой.

+8

Вау, я знал о '<$', но я только когда-либо использовал его, если вещь слева от него была постоянной, а правая была простой величиной ... Я никогда не думал о том, что произойдет, если я поставлю функцию слева: P Nice trick –

7

Ваш пример можно постепенно переписать в форме, которая более четко напоминает аппликативном:

do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 
  1. определение из do обозначения:

    many1 space >> (many1 digit >>= \ds -> return $ read ds) 
    
  2. определение $:

    many1 space >> (many1 digit >>= \ds -> return (read ds)) 
    
  3. определение .:

    many1 space >> (many1 digit >>= (return . read)) 
    
  4. третьего монада закон (ассоциативность):

    (many1 space >> many1 digit) >>= (return . read) 
    
  5. определение liftM (в бездокументарной do нотации):

    liftM read (many1 space >> many1 digit) 
    

Это (или должно быть, если я не испортил :)), идентичный поведению вашему примеру.

Теперь, если вы замените liftM с fmap с <$> и >> с *>, вы получите Прикладное:

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

Это справедливо, потому что liftM, fmap и <$>, как правило, должны быть синонимами, а >> и *>.

Все это работает, и мы можем это сделать, потому что исходный пример не использовал результат любого анализатора для создания следующего синтаксического анализатора.

+0

Прохладный! Другой способ написать 'читать <$ много1 пробел <*> много1 цифр'. :) Последнее предложение очень важно. Означает ли это, что этот стиль соответствует контекстно-свободным грамматикам, а более общие грамматики должны анализироваться монадическим стилем? –

+0

@WillNess Я не эксперт в этом, но я верю, что это так. –

 Смежные вопросы

  • Нет связанных вопросов^_^