在阅读了Anthony对与样式相关的解析器问题的回复后,我试图说服自己编写单子解析器仍然可以相当紧凑。
所以而不是
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
含义“序列但丢弃左侧提供的值和使用值”的运算符。
当然 << 对于 来说 是个坏名字,如果我们遵循与and相同的逻辑liftM2 const
,它会暗示这<<
等价于。flip >>
>>=
=<<
我没有在一个名称下找到“liftM2 const”。这是因为它没有那么有用吗?