Haskell 身份分析器

Haskell 身份分析器,haskell,parser-combinators,trifecta,Haskell,Parser Combinators,Trifecta,作为练习,我编写了一个字符串解析器,它只使用解析器和: 解析器的工作做得很好: parseString (stringParserWithChar "123") mempty "1234" -- Yields: Success '3' 但是,我对我应用的foldr的特定identityParser不满意。必须为pure选择一个任意字符,这似乎有点不妥 我的第一个直觉是使用mempty,但它不是幺半群。它是一个应用程序,但为空构成一个不成功的解析器 相反,我要寻找的是一个解析器,当与其他解析器结

作为练习,我编写了一个字符串解析器,它只使用解析器和:

解析器的工作做得很好:

parseString (stringParserWithChar "123") mempty "1234"
-- Yields: Success '3'
但是,我对我应用的
foldr
的特定
identityParser
不满意。必须为
pure
选择一个任意字符,这似乎有点不妥

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

相反,我要寻找的是一个解析器,当与其他解析器结合使用时,它作为一个中性元素工作。它不应该成功地执行任何操作,也就是说,不推进光标并让下一个解析器使用该字符

Trifecta或其他库中是否有如上所述的身份解析器?或者解析器不打算在
折叠中使用吗


该练习来自本书的解析器组合器一章


²同样有用的是,
解析器
是一个
备选方案
,因此是一个幺半群。
empty
函数源于
Alternative
,而不是
解析器的应用程序实例。

您不想用它来解析
字符串吗?现在,从函数签名可以看出,它解析一个
Char
,返回最后一个字符。仅仅因为你只有一个
Char
解析器并不意味着你不能创建一个
String
解析器

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

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

stringParserWithChar::String->Parser String
stringParserWithChar=遍历字符
展开,你会得到这样的结果

stringParserWithChar'::String->Parser String
stringParserWithChar'“=纯”
stringParserWithChar'(c:cs)=liftA2(:)(char c)(stringParserWithChar'cs)
--在上面使用do表示法时,请注意,您还可以对
--'char c'和'stringParserWithChar'cs',而只返回'pure(c:cs)'
--stringParserWithChar'(c:cs)=do

--让我们把你的折叠+反转改写成一个折叠来澄清发生了什么:

stringParserWithChar :: String -> Parser Char
stringParserWithChar =
  foldl (\otherParser c -> otherParser >> char c) identityParser
  where identityParser = pure '?'
任何时候你看到
foldl
被用来使用它的
Monad
实例构建一些东西,这都有点可疑[*]。这暗示你真的想要某种形式的一元折叠。让我们看看这里

import Control.Monad

-- foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
attempt1 :: String -> Parser Char
attempt1 = foldM _f _acc
这将遇到与您以前看到的相同的问题:您可以使用什么作为起始值?因此,让我们使用一个标准技巧,从
开始,也许是

-- (Control.Monad.<=<)
--   :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
stringParserWithChar :: String -> Parser Char
stringParserWithChar =
  maybe empty pure <=< foldM _f _acc
-(Control.Monad.mc)->(a->mb)->a->mc
stringParserWithChar::String->Parser Char
stringParserWithChar=

可能是空的纯解析字符串(stringParserWithChar“”)mempty“1234”
,您希望得到什么?如果失败了呢?引发运行时错误?成功得到什么结果?我个人会说它返回失败,说它期望得到空字符串。我明白了。也许您应该将该情况作为特殊情况处理,然后使用
foldr1
处理非空字符串,避免使用
identityParser
。旁白:任何时候您看到
foldr f n。相反
,您可以将其重写为
foldl(flip f)n
,而不会改变其含义,并且可能会提高性能。任何时候你看到
foldl f n。相反
,您几乎可以肯定地将其重写为
foldr(flip f)n
,这可能会增加惰性,也可能会提高性能。不过,在这种情况下,这两种观点似乎都不那么明智。
-- (Control.Monad.<=<)
--   :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
stringParserWithChar :: String -> Parser Char
stringParserWithChar =
  maybe empty pure <=< foldM _f _acc