Монадический эквивалент аппликативного <* - PullRequest
4 голосов
/ 24 октября 2011

Прочитав ответ Энтони на вопрос о парсере, связанном со стилем , я пытался убедить себя, что написание монадических парсеров все еще может быть довольно компактным.

Так что вместо

reference :: Parser Transc
reference = try $ do string "#{"
                     a <- number
                     char ','
                     b <- number
                     char ','
                     c <- number
                     char '}'
                     return $ Outside (a,b,c)

Мы можем просто иметь:

reference3 :: Parser Transc
reference3 = liftM3 (((Outside .).) .  (,,)) 
             (string "#{" >> number <<! char ',') 
             number
             (char ',' >> number <<! char '}') where 
               (<<!) = liftM2 const

Что очень похоже на аппликативную версию, предоставленную Энтони:

reference2 :: Parser Transc
reference2 = ((Outside .) .) . (,,) 
             <$> (string "#{" *> number2 <* char ',') 
             <*> number2 
             <*> (char ',' *> number2 <* char '}')

... за исключением оператора <<!, который концептуально аналогичен <*, который определяется как liftA2 const, означающее «последовательность, но отбрасывать значение и использовать значение, предоставленное слева».

Конечно << было бы плохим именем для <code>liftM2 const, было бы предположить, что << эквивалентно flip >>, если мы следуем той же логике, что и >>= и =<<.

Я не нахожу "const liftM2" под одним именем. Это потому что это не , что полезно?

1 Ответ

10 голосов
/ 24 октября 2011

Я не совсем вижу проблему. Каждая монада также является аппликативным функтором, поэтому вы можете просто использовать (*>) в монадических выражениях.

(На момент ответа (2011 год) Applicative не был суперклассом Monad, поэтому, возможно, было необходимо добавить соответствующий экземпляр класса.)

...