函数内部let而非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函数有一个2元组参数,其结果和树通过递归。。。这看起来不像哈斯克尔的方式。但我不知道为什么在let中有一个函数会产生这种差异。

在函数上添加一些类型,这样Haskell就可以更好地提示您哪里出了问题。如果没有类型,它会对你的意思做出假设,直到它达到矛盾,你不会知道哪个假设是错误的。

在这种情况下,混淆之处在于有时ftFO返回一个数字,有时它返回一个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中包含所希望的类型声明使错误消息更加容易理解。

最新更新