函数里面let not Num

Function inside let not Num

我有这些

data Fruit = Peach | Apple | Pear | Lemon | Fig deriving (Show,Eq)
data FTree = Bud | Split FTree FTree | Flat Fruit FTree deriving (Show,Eq)

这意味着计算输入水果类型的出现次数

ftreeFOccurs cft ft =
  let ftFO Bud = 0
      ftFO (Flat frt ft) = if (frt == cft) then (1 + (ftFO ft)) else (ftFO ft)
      ftFO (Split ft1 ft2) = (Split (ftFO ft1) (ftFO ft2))
  in ftFO ft

这是一棵典型的树

Split (Split Bud Bud) (Flat Fig (Flat Lemon (Flat Apple Bud)))

但是当我提交时 ftreeFOccurs 我得到这个错误

No instance for (Num FTree) arising from the literal `0'
    * In the expression: 0
      In an equation for `ftFO': ftFO Bud = 0

但是,类似的功能,

ftreeHeight Bud = 0
ftreeHeight (Flat frt ft) = 1 + ftreeHeight ft
ftreeHeight (Split ft1 ft2) = deeper (1 + ftreeHeight ft1) (1 + ftreeHeight ft2)
                              where deeper t1 t2 = if (t1 >= t2) then t1 else t2

有效。这是来自 The Little MLer 的 SML 问题的翻译,其中 occurs 函数有一个二元组参数,其中水果和树通过递归进行...这看起来不像 Haskell 方式。但是我不确定为什么在 let 中有一个函数会造成这种差异。

为您的函数添加一些类型,以便 Haskell 可以更好地提示您哪里出错了。没有类型,它会假设你的意思,直到出现矛盾,你不会知道哪个假设是错误的。

在这种情况下,混淆是有时 ftFO returns 一个数字,有时 returns 一个 FTree。这不是你想要的意思,但如果 Haskell 假设 FTree 可以被理解为一个数字,那么在技术上是允许的。所以 Haskell 继续这个想法一段时间,直到发现没有人说过如何将 FTree 解释为数字。

如前所述,我的错误是没有意识到第三种模式,

....
ftFO (Split ft1 ft2) = (Split (ftFO ft1) (ftFO ft2))
....

属于 FTree 类型,而该函数的目标是生成一个整数答案。此更正有效

ftreeFOccurs2 cft ft =
  let ftFO :: FTree -> Int
      ftFO Bud = 0
      ftFO (Flat frt ft) = if (frt == cft) then (1 + (ftFO ft)) else (ftFO ft)
      ftFO (Split ft1 ft2) = ftFO ft1 + ftFO ft2
  in ftFO ft

正如还指出的那样,在 let 中包含希望的类型声明使错误消息更容易理解。