haskell 如何将字符范围解析为元组

jpfvwuh4  于 2023-01-09  发布在  其他
关注(0)|答案(2)|浏览(108)

我想把"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),但只给出了不相关的结果。

2o7dmzc5

2o7dmzc51#

适用形式:

numRange = (,) <$> digitChar <* char '-' <*> digitChar

任何熟悉一元解析器的人都会立即理解它的作用。
liftM2(或等价的liftA2)形式或带签名函数的缺点:

pair :: Applicative f => f a -> f b -> f (a, b)
pair = liftA2 (,)

得到的解析器表达式:

pair (digitChar <* char '-') digitChar
pair digitChar (char '-' *> digitChar)

模糊了char '-'语法实际上并不是任何一个数字解析器的一部分的事实。因此,我认为这比公认的丑陋的应用语法更有可能令人困惑。

mwngjboj

mwngjboj2#

我有点期待已经有一个操作符可以对两个解析器进行排序,并在一个元组中返回两个结果。
有,正如你注意到的,它是liftA2 (,),但是,你不是在排序两个解析器,而是在排序三个解析器,即使你可以把它看作是两个解析器排序操作的“元序列”,这两个操作是不同的:
1.在digitChar <* char '-'中,忽略第二个解析器的结果(在我看来,<*看起来总是像<*>的拼写错误)。
1.在... <*> digitChar中,使用这两个结果。
如果您不喜欢直接使用应用运算符,请考虑使用do语法沿着ApplicativeDo扩展,并编写

numRange :: Parser (Char, Char)
numRange = do
    x <- digitChar
    char '-'
    y <- digitChar
    return (x,y)

它更长,但可以说比使用<*的两个版本中的任何一个都更具可读性,我总是认为这看起来像是<*>的拼写错误。

相关问题