如何P >> = F在解析器实例的作品?(How does p >>= f works

2019-10-28 16:07发布

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

instance Monad Parser where
    return a = Parser (\cs -> [(a,cs)])
    p >>= f = Parser (\cs -> concat [parse (f a) cs’ | (a,cs’) <- parse p cs])

上有一个解释文件

的(>> =)运算符是用于解析器测序操作。 使用拆解功能用于通过解析(分析器P)= p,则解析器P >>定义解析器= F首先应用解析器p来参数字符串CS,得到形式的结果的列表(A,CS'),其中一个是值和CS'是一个字符串。 对于每个这样的对,fa为被施加到串CS'的分析器。 其结果是一个列表的列表,然后将其连接起来,以得出的结果的最终名单。

但是,这仍然是不明确的。 任何人都可以用一些例子解释一下吗? 非常感谢。

Answer 1:

在Haskell解析器是一个的例子Monad 。 单子实际上是不仅仅是解析器更广泛的话题,但他们实际上做了很好的介绍的概念。 这里是如何在这里工作。

在解析器要能够认识到像规则(在BNF)

assignment ::= identifier "=" expression

在Haskell你会写这样的:

data Statement = 
    Assignment Identifier Expression
    | Block [Statement]  -- A block is a list of statements.
    | Conditional Expression Statement Statement
    | -- etc. 

identifier :: Parser Identifier  -- Implementation omitted.

literal :: String -> Parser ()   -- Implementation omitted.

expression :: Parser Expression   -- Implementation omitted.

assignment :: Parser Statement
assignment = do          -- Note the "do" here.
   ident <- identifier   
   literal "="          
   expr <- expression
   return (Assignment ident expr)   -- "return" doesn't mean what you think.

此捕获解析器的工作分配是子解析器的序列的想法:第一你解析标识符,则你认识到“=”,则解析在右手侧的表达式。 希望你可以看到BNF如何映射到Haskell代码。

Haskell中“做”语法是使用表达式语法糖>>=运算符(这被称为“绑定”)。 该assignment例如上述脱糖为以下(约:有东西约模式匹配失败,我跳过这里)

assignment = 
    identifier >>= (\ident ->
        operator "=" >>= (\dummy ->
           expression >>= (\expression -> return (Assignment ident expr))))

每个\ (称为“拉姆达”)引入了一个匿名函数。 该>>=操作符有两个参数。 在左边是解析器单子包裹起来的一些价值。 在右手边是一个函数,这个值,并返回一个新的包裹价值。 绑定运营商的工作是解开左边(这可能涉及做一些神奇的副作用),并把它传递给右侧的功能价值。 在这种情况下,神奇的副作用包括消费输入文本。

注意如何结合和匿名函数嵌套在去加糖版本。 在“做”的语法每个连续的行会转化为一个为前线内一个新的功能。 这意味着最后一个函数可以访问所有的变量在所有的功能至今。 它在象Haskell纯函数式语言建模分配块的一种方式。

我在评论中说,“回报”并不意味着你认为这意味着什么。 在Haskell是无关的控制流,它只是包装了一个单子的值(在这种情况下Parser ),而不会造成任何副作用本身。

这种特殊的解析器生成的结果列表。 也就是说,而不是在每一步上一个真正解析决定,当它遇到模棱两可的东西它产生的结果列表。 绑定运算符采用每一结果到目前为止,并将其传递到其右边的功能,这又可能会再次产生多个结果。 或解析器可以产生任何结果在这种情况下该分支被放弃。 因此,每个步骤与结果列表开始,下一步给出的结果的列表,然后将其由“CONCAT”功能折回到结果的平面列表的列表。

Monad在你的问题给出类是标准库的一部分。 碰巧有很多适用于所有单子有用的功能,所以给他们一个共同的界面效果很好。 在的情况下, Parser绑定操作者的类型

(>>=) :: Parser a -> (a -> Parser b) -> Parser b

return有型

return :: a -> Parser a

默想这些类型的,我给了什么约束和回报做了描述,您可以实现单子启发。



文章来源: How does p >>= f works in Parser instance?