我有这些
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
中包含所希望的类型声明使错误消息更加容易理解。