我一直在尝试使用Haskell编写一个简单的映射函数,我遇到了以下问题:
data Tree a = Leaf a | Node (Tree a) (Tree a) deriving(Show)
let g (Leaf l) = Leaf(l+1)
let map g (Leaf l) = g(l)
let lf = (Leaf 2)
对于g(lf)
,输出为Leaf 3
除外,
但对于map g lf
我收到以下错误:
Couldn't match type `Integer' with `Tree a0'
Expected type: Tree (Tree a0)
Actual type: Tree Integer
In the second argument of `map', namely `lf'
In the expression: map g lf
In an equation for `it': it = map g lf
我不知道为什么会收到此错误,如果有人能指出我的解决方案,我将不胜感激。
答案 0 :(得分:1)
这正是类型系统,显示您的程序逻辑无法解决。我们可以通过手动添加大量额外类型信息来跟踪细节,看看我们的直觉是否与检查器的细节相匹配。
data Tree a = Leaf a | Node (Tree a) (Tree a) deriving (Show)
g :: Num a => Tree a -> Tree a
g (Leaf l) = Leaf (l + 1)
map :: (a -> b) -> Tree a -> b
map g (Leaf l) = g(l)
lf :: Num a => Tree a
lf = (Leaf 2)
现在我们来看看失败的表达
(map :: (a -> b) -> Tree a -> b)
(g :: Num c => Tree c -> Tree c)
(lf :: Num d => Tree d)
我们注意到(a -> b)
必须与(Num c => Tree c -> Tree c)
匹配,我们a
为Tree c
,b
也是如此。
(map g :: Tree (Tree c) -> Tree c)
(lf :: Num d => Tree d)
现在我们注意到d
必须与给我们的Tree c
匹配
map g lf :: Num (Tree c) => Tree (Tree c) -> Tree c
现在我们知道我们现在正在沉没,因为Tree
不是数字,但你得到的错误略有不同。它说Tree c
不是Integer
。
这是因为Haskell在您不提供类型签名时会尝试提供帮助并猜测您可能正在处理的具体类型。当它这样做时,它有时会选择比严格可能的更多的多态。在这种情况下,它决定lf :: Tree Integer
而不是lf :: Num d => Tree d
,因为前者更具体。