我想把"0-9"
这样的字符串解析成('0', '9')
,但是我觉得我的两次尝试看起来有点笨拙。
numRange :: Parser (Char, Char)
numRange = (,) <$> digitChar <* char '-' <*> digitChar
numRange' :: Parser (Char, Char)
numRange' = liftM2 (,) (digitChar <* char '-') digitChar
我有点期待已经有一个操作符可以对两个解析器排序,然后返回一个元组中的两个结果,如果有的话,我就找不到它了,而且我也很难弄清楚在hoogle上搜索所需的签名。
我尝试了基于<*
签名的Applicative f => f a -> f b -> f (a, b)
,但只给出了不相关的结果。
2条答案
按热度按时间2o7dmzc51#
适用形式:
任何熟悉一元解析器的人都会立即理解它的作用。
liftM2
(或等价的liftA2
)形式或带签名函数的缺点:得到的解析器表达式:
模糊了
char '-'
语法实际上并不是任何一个数字解析器的一部分的事实。因此,我认为这比公认的丑陋的应用语法更有可能令人困惑。mwngjboj2#
我有点期待已经有一个操作符可以对两个解析器进行排序,并在一个元组中返回两个结果。
有,正如你注意到的,它是
liftA2 (,)
,但是,你不是在排序两个解析器,而是在排序三个解析器,即使你可以把它看作是两个解析器排序操作的“元序列”,这两个操作是不同的:1.在
digitChar <* char '-'
中,忽略第二个解析器的结果(在我看来,<*
看起来总是像<*>
的拼写错误)。1.在
... <*> digitChar
中,使用这两个结果。如果您不喜欢直接使用应用运算符,请考虑使用
do
语法沿着ApplicativeDo
扩展,并编写它更长,但可以说比使用
<*
的两个版本中的任何一个都更具可读性,我总是认为这看起来像是<*>
的拼写错误。