这里有两个问题。首先,数据类型:
data Tree a = Nil | Node a (Tree left) (Tree right) deriving (Eq, Show, Read)
-- ^left? ^right?
在您的数据定义,您使用的left
和right
,但这些都是在数据定义的头部形成不,因此这些不会打字参数。你可能想说:
data Tree a = Nil
| Node { value :: a, left :: Tree a, right :: Tree a}
deriving (Eq, Show, Read)
但现在我们仍然得到一个错误:
hs.hs:5:1: Warning:
Pattern match(es) are non-exhaustive
In an equation for ‘get’: Patterns not matched: _ (Node _ _ _)
Ok, modules loaded: Main.
这里的问题是,哈斯克尔不知道两个值只能是<
,==
或>
)。
如果你写Ord
的instance
,那么你有一个“联系人”,你将定义一个总订货。换句话说,对于任何两个值x
和y
,它认为x < y
,x > y
或x == y
。然而问题是Haskell确实不是知道的。对于Haskell,函数(<)
,(==)
或(>)
中的任何函数都可导致True
或False
。因此 - 因为编译器是总是保守 - 它会考虑有两个值的情况下,使所有x < y
,x == y
和x > y
失败(说你假设会写foo x y
,bar x y
和qux x y
那么这绝对会偏偏这是因为它们三个黑匣子函数)。您可以通过在最后一种情况下写otherwise
解决它:
get :: Ord a => a -> Tree a -> Maybe a
get _ Nil = Nothing
get x (Node v lt rt)
| x == v = Just x
| x < v = get x lt
| otherwise = get x rt
otherwise
是True
的别名因此没有可能不采取该分支。所以,现在的保守编译理解的是,无论什么样的x
和y
的值,它总是会一些分支,因为如果不采取前两种,它会肯定取最后一个。
你可能会认为这是奇怪的,但由于通常不会在正式语言(仅在文档中,因此自然语言)中规定的合同,编译器没有意味着要知道:你可以作为一个程序员决定不尊重合同(但请注意,这是一个坏主意非常)。即使你通常以程序员的身份编写正式合同,你仍然可以决定不尊重它,而且编译器不能总是对正式合同进行必要的逻辑推理。
你能显示你得到的警告吗?为什么在你的函数签名中使用'AATree'而不是'Tree'? –
对不起,我复制了错误的代码,我改变了它,但它只是aatree/tree的区别! – mistysch
警告:警告:[-Wincomplete-patterns] 模式匹配并非详尽 在'get'的等式中:模式不匹配:_(节点_ _ _) – mistysch