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])
有一个解释
(>> =)运算符是解析器的排序运算符。用一个 由parse(Parser p)= p定义的解析器的解构函数 解析器p >> = f首先将解析器p应用于参数字符串 cs给出形式(a,cs’)的结果列表,其中a是一个值 而cs是一个字符串。对于每个这样的对,f a是一个解析器,它是 应用于字符串cs'。结果是列表列表,即 然后连接起来以给出最终结果列表。
但这还不清楚。谁能举例说明?非常感谢。
答案 0 :(得分:1)
在Haskell中,解析器是Monad
的示例。 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中的“ do”语法是使用>>=
运算符(称为“ bind”)的表达式的语法糖。上面的assignment
示例将糖分解为以下内容(大约:我在这里跳过了有关模式匹配失败的内容)
assignment =
identifier >>= (\ident ->
operator "=" >>= (\dummy ->
expression >>= (\expression -> return (Assignment ident expr))))
每个\
(称为“ lambda”)都引入了一个匿名函数。 >>=
运算符采用两个参数。左侧是包裹在Parser monad中的一些值。右侧是一个函数,该函数接受此值并返回新的包装值。绑定运算符的工作是解开左侧的值(这可能涉及做一些魔术上的副作用)并将其传递给右侧的函数。在这种情况下,魔术的副作用包括消耗输入文本。
请注意绑定和匿名函数如何嵌套在已删除版本中。 “ do”语法中的每一行都将转换为上一行中的一个新函数。这意味着到目前为止,最后一个函数可以访问所有函数中的所有变量。它是一种使用像Haskell这样的纯函数式语言对一组作业进行建模的方法。
我在评论中说,“返回”并不意味着您认为的含义。在Haskell中,它与控制流无关,它只是将一个值包装为monad(在这种情况下为Parser
),而不会引起任何副作用。
此特定的解析器生成结果列表。也就是说,当遇到任何歧义时,它会生成一个结果列表,而不是在每个步骤上都确定一个真实解析。绑定运算符将每个结果取到最远,然后将其传递给右边的函数,这又可能再次生成多个结果。否则解析器可能不会产生任何结果,在这种情况下该分支将被放弃。因此,每个步骤都从结果列表开始,然后下一步给出结果列表的列表,然后通过“ concat”功能将其折叠成平坦的结果列表。
您的问题中提供的Monad
类是标准库的一部分。碰巧有很多有用的功能适用于所有monad,因此为它们提供一个通用的接口就可以很好地工作。对于Parser
,绑定运算符的类型为
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
和return
具有类型
return :: a -> Parser a
沉思这些类型以及我对绑定和返回所做的描述,您可能会获得一元启示。