【问题标题】:Monad Parser - Couldn't match expected type ‘[(b, String)]’ with actual type ‘Parser b’Monad Parser - 无法将预期类型“[(b, String)]”与实际类型“Parser b”匹配
【发布时间】:2020-04-08 03:06:12
【问题描述】:

我正在使用 G.Hutton 的“在 Haskell 中编程”学习 Haskell。我正在关注 Monadic Parser 的第 13 章。 首先,我定义了一个类型 Parser:

newtype Parser a = P (String -> [(a, String)])

然后,一个解析函数

parse:: Parser a -> String -> [(a, String)]

我将 Parser 设为 Monad

instance Monad Parser where
--return :: a -> Parser a
 return v =  P(\inp -> [(v, inp)])

--(>>=) :: Parser a -> (a -> Parser b) -> Parser b
 p >>=  g = P (\inp -> case parse p inp of
  [] -> []
  [(v, out)] -> parse (g v) out)

我的问题在 Monad 实例的最后一行 为什么会这样

[(v, out)] -> parse (g v) out)

不是这个

[(v, out)] -> (g v))

>>= 返回解析器 b,而不是 [(b, String)]。事实上,g v 是解析器。

我知道我错了,但我不明白为什么。

【问题讨论】:

  • 你把它包装在一个P构造函数中,因此它应该是String -> [(a,String)]类型。话虽如此,解析器还没有完成,因为列表可能包含多个元素。

标签: parsing haskell types functional-programming monads


【解决方案1】:

>>= 返回解析器 b,而不是 [(b, String)]。事实上,g vParser

这是正确的,但我们正在构造一个带有外部PParser。确实:

p >>=  g = P (\inp -> case parse p inp of
  [] -> []
  [(v, out)] -> parse (g v) out)

注意P 紧跟在= 之后。 lambda 表达式\inp -> … 因此必须具有String -> [(b, String)] 类型,而不是Parser。我们使用parse 评估解析器,因为它充当“getter”以从g v 中获取函数。

但是,您对 >>= 的实现并不完整。实际上,这是一个回溯解析器,列表可能不包含任何元素(无选项)、一个元素或 多个 元素。因此,我们应该执行如下映射:

p >>= g = P (
    \inp -> concatMap (\(v, out) -> parse (g v) out) (parse p inp)
  )

或者我们可以使用为列表定义的绑定运算符>>=

p >>= g = P (
    \inp -> parse p inp >>= \(v, out) -> parse (g v) out
  )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-02
    • 2021-11-13
    • 1970-01-01
    • 2015-04-15
    相关资源
    最近更新 更多