【问题标题】:Why do I get these type errors?为什么我会收到这些类型错误?
【发布时间】:2016-02-11 01:42:55
【问题描述】:

我有一个数据类型:

data Tree = Empty | Node Int Tree Tree

我想要功能

nodeDepth :: Tree -> [(Int, Int)] 

每个节点一对。第一个元素是标签(值),第二个是它的深度。

我的意图(原始代码)是这样的:

nodeDepth (Node label left right) = zip nodeDepth' (Node label left right) [0]
nodeDepth' Empty _ = []
nodeDepth' (Node label left right) [level] = label : nodeDepth' (Node label left right) level : (1 + level)

但这不起作用。

怎么了?我正在使用 Frege REPL

Error message are like :

E <console>.fr:22: t19906 occurs in type [t19906] rendering expression level{19727} untypable.

E <console>.fr:22: type error in  expression level
    type is   t19906
    used as   [t19906]

E <console>.fr:22: type error in  expression
    nodeDepth' (Node label left right) level:+ 1 level
    type is   [[t19909]]
    used as   [Int]


E <console>.fr:22: [[Int]] is not an instance of Num


E <console>.fr:20: type error in expression nodeDepth'
    type is apparently [t19961]
    used as function


H <console>.fr:20: too many or too few arguments perhaps?


E <console>.fr:20: type error in  expression Node label left right
    type is   Tree
    used as   [t19964]


E <console>.fr:20: type error in expression
    zip nodeDepth' (Node label left right)
    type is apparently [(t19961,t19964)]
    used as function


H <console>.fr:20: too many or too few arguments perhaps?


W <console>.fr:20: application of nodeDepth will diverge.

【问题讨论】:

  • 弗雷格differs from regular Haskell;我认为使用frege 标签而不是haskell 更合适。
  • 无法获取节点的深度。你只能得到它的高度(例如离树叶最长的距离)那么你想要得到什么?
  • @Zeta 感谢您的编辑。如果他使用 ghci,类型错误将是同构的。但没关系,我们关心这个。 :)
  • @Zeta 我认为添加 Haskell 标签是值得的,因为这个问题中出现的问题对于 Haskell 来说也是一样的,而标签 frege “限制”了问题的公开性。

标签: tree frege


【解决方案1】:

至于错误,请考虑以下行:

nodeDepth (Node label left right) = zip nodeDepth' (Node label left right) [0]

由于 Haskell 函数式应用程序关联到左侧, zip 将函数 nodeDepth' 作为其第一个参数。要修复此特定错误,您可能需要编写:

zip (nodeDepth' (Node label left right)) [0]

但是你仍然缺少 nodeDepth' 的第二个参数,所以括号中的表达式只返回一个函数而不是一个列表。

另一个错误是当您为非空树定义 nodeDepth' 时:您的模式匹配 [level] 将 level 作为单个元素捕获并在同一行将其传递给自身。这只能通过假设 level 本身是一个列表来解决,但这也没有太大意义,因为在行尾添加假设 level 是 Numeric 类型。

nodeDepth' (Node label left right) [level] = label : nodeDepth' (Node label left right) level : (1 + level)

以下函数 nodeDepth 使用深度优先搜索遍历树并构造标签列表和各个节点的深度。

data Tree = Empty | Node Int Tree Tree

wikiTree = Node 2 (Node 7 (Node 2 Empty Empty) (Node 6 (Node 5 Empty Empty) (Node 11 Empty Empty))) (Node 5 Empty (Node 9 (Node 4 Empty Empty) Empty))

nodeDepth :: Tree -> [(Int, Int)]
nodeDepth Empty = []
nodeDepth (Node label left right) = nodeDepthAccumulator (Node label left right) 0

nodeDepthAccumulator :: Tree -> Int -> [(Int, Int)]
nodeDepthAccumulator Empty _ = []
nodeDepthAccumulator (Node label left right) depth = (label,depth) : nodeDepthAccumulator left (depth+1) ++ nodeDepthAccumulator right (depth+1)

在你得到的示例 wikiTree 上执行 nodeDepth:

> nodeDepth wikiTree
> [(2, 0),(7, 1),(2, 2),(6, 2),(5, 3),(11, 3),(5, 1),(9, 2),(4, 3)]

如您所料。

【讨论】:

    【解决方案2】:

    这个:

    zip nodeDepth' (Node label left right) [0]
    

    zip 函数导出两个列表,但 nodeDepth'(Node ...) 都不是列表。然后将结果(这是一个列表)应用到其他列表[0],这解释了倒数第二条消息。我猜你是想写

    zip (nodeDepth' (Node label left right)) [0]
    

    但即使在这种情况下,也缺少 nodeDepth' 的参数以使括号中的表达式成为列表。

    nodeDepth' 的第二个定义也不会编译,原因如下:

    • 使用[level] 模式匹配一​​个单元素列表,并调用单元素level。美好的。但是您使用 level 作为 nodeDepth' (这是一个列表)的第二个参数,并在表达式 1+level 中使用它作为数字。
    • 在类似的表达式中

      a:b:c

    c 必须是列表(不在您的示例中),b 不能是列表,并且必须与 a 具有相同的类型。但是 nodeDepth' 应该返回一个列表。因此,整个 RHS 毫无意义,因此您会遇到很多错误。

    这里有一个提示:由于您显然不希望 level 成为一个列表,并且没有任何地方真正将列表传递给 nodeDepth',所以将模式 [level] 替换为 level 不是更好吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      • 2011-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多