在Anthony's response上阅读a style-related parser question之后,我试图说服自己编写monadic解析器仍然可以相当紧凑。
所以而不是
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
这与Anthony提供的应用版非常相似:
reference2 :: Parser Transc
reference2 = ((Outside .) .) . (,,)
<$> (string "#{" *> number2 <* char ',')
<*> number2
<*> (char ',' *> number2 <* char '}')
... <<!
运算符除外,它在概念上类似于<*
,其定义为liftA2 const
,表示“序列但丢弃值和使用值提供给左侧”。< / p>
当然&lt;&lt;如果我们遵循与liftM2 const
和<<
相同的逻辑,那么flip >>
就相当于>>=
,这可能是=<<
的错误名称。
我没有在单个名称下找到“liftM2 const”。这是因为它不是 有用吗?
答案 0 :(得分:10)
我不太明白这个问题。每个monad也是一个applicative functor,所以你也可以在monadic表达式中使用(*>)
。
(在本回答时(2011年),Applicative
不是Monad
的超类,因此可能需要添加相应的类实例。)