【问题标题】:Function definition has type error in function many函数定义在函数 many 中有类型错误
【发布时间】:2021-01-15 11:29:03
【问题描述】:

我最近开始学习 Haskell,目前正在研究“用于解析的高阶函数”论文。你可以找到它Here.

论文定义了一个名为many的函数。

许多 :: parser * ** -> parser * [**] many p = ((p $then many p) $using cons) $alt (succeed [])

我正在尝试将其转换为 Haskell。

succeed v inp = [(v, inp)]

fail' inp = []

satisfy p [] = fail' []
satisfy p (x:xs)
  | p x = succeed x xs
  | otherwise = fail' xs

literal x = satisfy (==x)

alt' p1 p2 = \inp -> p1 inp ++ p2 inp

then' p1 p2 = \inp -> [((v1, v2), out2) | (v1, out1) <- p1 inp, (v2, out2) <- p2 out1]

using' p f = \inp -> [(f v, out) | (v, out) <- p inp]

many' p = ((p `then'` (many' p)) `using'` (:)) `alt'` (succeed [])

我已经单独测试了所有部件,它们工作正常。但是许多人的定义给了我错误。我似乎无法弄清楚是什么问题。我正在按照论文中提到的方式进行操作。

Main.hs:19:56: 错误: • 无法将类型“[a0]”与“[(a, b)] -> [(a, b)]' 匹配 预期类型:t -> [([(a, b)] -> [(a, b)], t)] 实际类型:t -> [([a0], t)] • 在‘alt’’的第二个参数中,即‘(succeed [])’ 在表达式中: ((p `then'` (many' p)) `using'` (:)) `alt'` (succeed []) 在“许多”的等式中: many' p = ((p `then'` (many' p)) `using'` (:)) `alt'` (succeed []) • 相关绑定包括 p :: t -> [(a, t)] (绑定在 Stum.hs:19:7) many' :: (t -> [(a, t)]) -> t -> [(b, t)] (绑定在 Stum.hs:19:1) | 19 | many' p = ((p `then'` (many' p)) `using'` (:)) `alt'` (succeed []) | 失败,未加载任何模块。 前奏>

【问题讨论】:

  • 今后,请不要包含文本图像(代码、错误消息等),除非问题特别涉及文本颜色、字体等。有视觉障碍的人无法访问文本图像人并阻碍搜索。

标签: haskell


【解决方案1】:

如果您在所有顶级定义中都有类型,这将更容易理解。

无论如何,我认为问题在于using' 和柯里化之间的交互。我注意到then' 将两个值解析为一对,并且您正在解析的示例代码将cons 应用于该对,以从对元素创建一个列表作为列表的头部和尾部。但是(:) 是柯里化的——如果你将它应用于一对,那么这对只是列表的头部,它仍然需要第二个参数作为尾部。您应该决定是否要 using' 采用柯里化函数。如果您想尽可能贴近您关注的论文,您将保留using' 的定义,但将many' 更改为

many' p = ((p `then'` (many' p)) `using'` uncurry (:)) `alt'` (succeed [])

uncurryPrelude 公开的一个简单的辅助函数,恰好正好解决了这个问题。

注意:所有这些都未选中。这是我可以在不查看所涉及的类型的情况下提供的最佳快速猜测。

这里有更多解释,试图让这更容易理解:

(:) 的类型为 a -&gt; [a] -&gt; [a]uncurry (:)(或等价的(\(h, t) -&gt; h:t),以防uncurry 有点难以让你立刻理解)类型为(a, [a]) -&gt; [a]。在完成其余工作时,您应该牢记这种差异。

请注意,then'((v1, v2), out2) 中的解析值元组化。请注意,using' 将解析后的值作为一个整体转换为 (f v, out)。当它们被链接在一起时,它最终会沿着f (v1, v2) 的行计算一个表达式。鉴于many' 将如何使用then'v1 将是单个解析结果,v2 将是后续解析结果的列表。您想将它们组合成一个更大的列表,(v1:v2)。您需要通过将一些函数f 应用于(v1, v2) 来做到这一点。现在回到(:)uncurry (:) 之间的区别。当提供为 f 时,其中只有一个具有正确的类型来执行此操作。

我希望这个扩展的解释能让你更容易看到发生了什么。

【讨论】:

  • 天哪,这太有效了。我仍然不明白到底发生了什么。我明天需要再次阅读您的答案。我的脑袋无法理解你做了什么
猜你喜欢
  • 2017-03-29
  • 2023-02-10
  • 2014-05-26
  • 2014-07-29
  • 2019-02-05
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
  • 1970-01-01
相关资源
最近更新 更多