正如 chi 所指出的,最好从类型签名开始:
mapTree :: (a -> b) -> Tree a -> Tree b
如果你这样做了,你会得到两个类型错误,每个错误都指向你的代码中的一个不同的错误。第一个:
[1 of 1] 编译 Main (.code.tio.hs, .code.tio.o)
.code.tio.hs:6:21: 错误:
• 无法将预期类型“树 b”与实际类型“b”匹配
‘b’ 是一个刚性类型变量,由
类型签名:
mapTree::forall a b. (a -> b) -> 树 a -> 树 b
在 .code.tio.hs:5:1-39
• 在表达式中:func []
在“mapTree”的等式中:mapTree func Leaf = func []
• 相关绑定包括
func :: a -> b(绑定在 .code.tio.hs:6:9)
mapTree :: (a -> b) -> 树 a -> 树 b(绑定在 .code.tio.hs:6:1)
|
6 | mapTree func 叶 = func []
| ^^^^^^^
出现这种情况是因为第一种情况应该产生Tree b,但是将func 应用于参数只能产生b 类型的东西。
第二个:
.code.tio.hs:6:26: 错误:
• 无法将预期类型“a”与实际类型“[a0]”匹配
‘a’ 是一个刚性类型变量,由
类型签名:
mapTree::forall a b. (a -> b) -> 树 a -> 树 b
在 .code.tio.hs:5:1-39
• 在‘func’的第一个参数中,即‘[]’
在表达式中:func []
在“mapTree”的等式中:mapTree func Leaf = func []
• 相关绑定包括
func :: a -> b(绑定在 .code.tio.hs:6:9)
mapTree :: (a -> b) -> 树 a -> 树 b(绑定在 .code.tio.hs:6:1)
|
6 | mapTree func 叶 = func []
| ^^
发生这种情况是因为当 func 期待 a 类型的参数时,您将 func 应用于某种类型的列表。
假设您通过将第一种情况更改为来修复这些错误
mapTree _func Leaf = Leaf
(我在func 前加了一个下划线。按照惯例,这表明它在这种情况下是故意不使用的。如果您应该启用编译器警告,这将阻止 GHC 警告您未使用的变量绑定.)
现在你会得到一个新的不同的错误:
.code.tio.hs:7:65:错误:
• 无法将预期类型“b”与实际类型“a”匹配
‘a’ 是一个刚性类型变量,由
类型签名:
mapTree::forall a b. (a -> b) -> 树 a -> 树 b
在 .code.tio.hs:5:1-39
‘b’ 是一个刚性类型变量,由
类型签名:
mapTree::forall a b. (a -> b) -> 树 a -> 树 b
在 .code.tio.hs:5:1-39
• 在‘Branch’的第二个参数中,即‘a’
在表达式中:
分支 (mapTree func left) a (mapTree func right)
在“mapTree”的等式中:
mapTree func(左右分支)
= 分支 (mapTree func left) a (mapTree func right)
• 相关绑定包括
右 :: 树 a(绑定在 .code.tio.hs:7:29)
a :: a(绑定在 .code.tio.hs:7:27)
left :: 树 a(绑定在 .code.tio.hs:7:22)
func :: a -> b(绑定在 .code.tio.hs:7:9)
mapTree :: (a -> b) -> 树 a -> 树 b(绑定在 .code.tio.hs:6:1)
|
7 | mapTree func (Branch left a right) = Branch (mapTree func left) a (mapTree func right)
| ^
这是因为您忘记将func 应用于存储在节点中的值。您需要将 a 转换为 b 而您忘记了。