Прочитав ответ Энтони на вопрос о парсере, связанном со стилем , я пытался убедить себя, что написание монадических парсеров все еще может быть довольно компактным.
Так что вместо
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" под одним именем. Это потому что это не , что полезно?