首页 > 解决方案 > 身份解析器

问题描述

作为练习¹,我编写了一个仅使用char解析器和Trifecta的字符串解析器:

import           Text.Trifecta
import           Control.Applicative            ( pure )

stringParserWithChar :: String -> Parser Char
stringParserWithChar stringToParse =
  foldr (\c otherParser -> otherParser >> char c) identityParser
    $ reverse stringToParse
  where identityParser = pure '?' -- ← This works but I think I can do better

解析器可以很好地完成它的工作:

parseString (stringParserWithChar "123") mempty "1234"
-- Yields: Success '3'

identityParser然而,我对我申请的具体内容并不满意foldr。必须为pure.

我的第一个直觉是使用memptyParser不是幺半群。它一个应用程序,但empty构成一个不成功的解析器²。

相反,我正在寻找的是一个解析器,它在与其他解析器结合时作为中性元素工作。它应该什么都不做,即不推进光标并让下一个解析器使用该字符。

Trifecta 或其他库中是否有上述身份解析器?还是解析器不打算在 a 中使用fold


¹ 该练习来自Haskell Programming from first principle一书的解析器组合器章节。

² 正如cole 所指出的Parser是一个Alternative,因此是一个幺半群。该empty函数源于Alternative, 而不是Parser的应用实例。

标签: haskellparser-combinatorstrifecta

解决方案


您不希望它解析 aString吗?现在,从函数签名中可以看出,它解析 a Char,返回最后一个字符。仅仅因为你只有一个Char解析器并不意味着你不能制作一个String解析器。

我将假设您要解析一个字符串,在这种情况下,您的基本情况很简单:您identityParser的只是pure "".

我认为这样的事情应该有效(并且应该按照正确的顺序,但可能会颠倒过来)。

stringParserWithChar :: String -> Parser String
stringParserWithChar = traverse char

展开,你会得到类似的东西

stringParserWithChar' :: String -> Parser String
stringParserWithChar' "" = pure ""
stringParserWithChar' (c:cs) = liftA2 (:) (char c) (stringParserWithChar' cs)
-- the above with do notation, note that you can also just sequence the results of
-- 'char c' and 'stringParserWithChar' cs' and instead just return 'pure (c:cs)'
-- stringParserWithChar' (c:cs) = do
--   c'  <- char c
--   cs' <- stringParserWithChar' cs
--   pure (c':cs')

如果它们不起作用,请告诉我,因为我现在无法测试它们……</p>

关于幺半群的题外话

我的第一个直觉是使用 mempty 但 Parser 不是幺半群。

啊,但事实并非如此。ParserAlternative,它是Monoid。但是您实际上并不需要查看AlttypeclassData.Monoid来理解这一点;Alternative的类型类定义看起来就像 aMonoid的:

class Applicative f => Alternative f where
  empty :: f a
  (<|>) :: f a -> f a -> f a
  -- more definitions...
class Semigroup a => Monoid a where
  mempty  :: a
  mappend :: a -> a -> a
  -- more definitions...

不幸的是,你想要的东西更像是一个产品而不是一个Alt,但这就是默认行为的Parser作用。


推荐阅读