haskell – 了解attoparsec实现(第2部分)

我目前正在尝试研究和理解attoparsec库的源代码,但有些细节我自己无法弄清楚.例如,Parser类型的定义:

newtype Parser i a = Parser {
      runParser :: forall r.
                   State i -> Pos -> More
                -> Failure i (State i)   r
                -> Success i (State i) a r
                -> IResult i r
    }

newtype Pos = Pos { fromPos :: Int }
            deriving (Eq, Ord, Show, Num)

data IResult i r =
    Fail i [String] String
  | Partial (i -> IResult i r)
  | Done i r

type Failure i t   r = t -> Pos -> More -> [String] -> String
                       -> IResult i r
type Success i t a r = t -> Pos -> More -> a -> IResult i r

我还没有完全理解的是类型参数r的用法.如果我像这样定义runParser的类型签名会有什么不同:

状态i – > Pos – >更多 – >失败i(状态i)a – >成功i(状态i)a a – >我爱你

你能帮我理解一下吗?在这种情况下确切意味着为什么有必要在runParser的类型签名中使用它?

很多thx提前!

更新:进一步澄清我的问题:我目前不明白的是为什么有必要首先引入类型参数r.可以想象,Parser类型也可以像这样定义:

newtype Parser i a = Parser {
      runParser ::
                   State i -> Pos -> More
                -> Failure i (State i) a
                -> Success i (State i) a
                -> IResult i a
}

data IResult i a =
    Fail i [String] String
    | Partial (i -> IResult i a)
    | Done i a

type Failure i t a  = t -> Pos -> More -> [String] -> String
                      -> IResult i a
type Success i t a = t -> Pos -> More -> a -> IResult i a

其中根本不使用类型参数r.我的问题是为什么这个定义会“错误”以及它会带来什么问题……

最佳答案 attoparsec创建连续传递样式(CPS)解析器

没有forall我们将无法链接

解析器在一起.

这是一个大大简化的版本
涉及的类型和bindP的定义 – monadic绑定运算符.
我们已经消除了故障延续和输入源.

{-# LANGUAGE Rank2Types #-}

type IResult r = r
type Success a r = a -> IResult r  -- Success a r == a -> r

newtype Parser a = Parser {
      runParser :: forall r. Success a r
                -> IResult r
    }

bindP :: Parser a -> (a -> Parser b) -> Parser b
bindP m g =
    Parser $\ks -> runParser m $\a -> runParser (g a) ks
                                                  -----
                                                  -----

注意,成功r只是函数类型a – >河

如果我们用以下命令替换runParser的定义:

runParser :: Success a a -> IResult a

我们会在上面带下划线的位置出现类型错误.
要理解这一点,可以解决以下类型:

ks                                      :: Success b b
runParser m $\a -> runParser (g a) ks  :: IResult b
\a -> runParser (g a) ks                :: Success b b  == b -> b
a :: b

但是从表达式(g a)我们也可以得出结论a a有a型
这给了我们类型错误.

基本上Parser a可以被认为是一种方法(或计算)
生成类型a和runParser p ks的值是的方法
获取该值并将其提供给需要a的函数.
连续函数ks可以具有类型a – > r对于任何r –
唯一的要求是它的输入类型是a.
通过使用Success a a定义runParser,我们限制了
runParser对类型a的函数的适用性 – >一个.这就是我们的原因
想要将runParser定义为:

runParser :: Parser a -> (a -> r) -> r

这种CPS风格是一种非常不同的解析方法
Monadic Parsing in Haskell

点赞