检查列表是否在升序(Haskell)

时间:2015-06-04 00:32:10

标签: haskell

我正在编写一个函数来检查树是否是BST。我所尝试的只是按顺序遍历列表打印树,然后检查列表是否在增加。但是我遇到了这个错误:

Couldn't match expected type `a' against inferred type `[t]'
  `a' is a rigid type variable bound by
      the type signature for `checkList' at BST.hs:24:18
In the pattern: x : y : xs
In the pattern: [x : y : xs]
In the definition of `checkList':
    checkList [x : y : xs] = x <= y && checkList (y : xs)

这是我到目前为止(只有一个checkList函数)。

checkList :: (Ord a) => [a] -> Bool
checkList [] = True
checkList [x] = True
checkList [x:y:xs] = x <= y && checkList (y:xs)

3 个答案:

答案 0 :(得分:7)

你想:

checkList :: (Ord a) => [a] -> Bool
checkList [] = True
checkList [x] = True
checkList (x:y:xs) = x <= y && checkList (y:xs)

当您尝试在最终模式中使用[ ]时,您说“匹配包含x:y:xs(也是列表!)的列表作为其唯一元素”。哪个与[a]类型不匹配。

答案 1 :(得分:2)

使用foldl'

时有些难看
checkList :: Ord a => [a] -> Bool
checkList xs = fst $ foldl' (\(b,x1) x2 -> (b && x1 <= x2,x2)) (True,head xs) xs

注意:由于懒惰的评估,使用head xs就可以了。

答案 2 :(得分:2)

通常的做法是让你的树可折叠:

data BST a = Node (BST a) a (BST a) | Leaf

-- Use `deriving Foldable` or this instance
instance Foldable BST where
  foldMap _ Leaf = mempty
  foldMap f (Node l v r) =
    foldMap f l <> (f v <> foldMap f r)

然后你可以跳过转换到这样的列表。这类似于bmk的答案,但避免使用head

-- Is this increasing? If so, what is the maximum?
data Result a = Empty | NotInc | Inc a

finalInc :: Result a -> Bool
finalInc NotInc = False
finalInc _ = True 

increasing :: (Foldable f, Ord a) => f a -> Bool
increasing = finalInc . foldl' go Empty where
  go Empty y = Inc y
  go NotInc _ = NotInc
  go (Inc x) y
    | x <= y = Inc y
    | otherwise = NotInc

警告!警告!

此检查的属性比传统的二进制搜索树属性弱,并且弱于弱化该属性的常用方法。特别是,您通常希望至少确保每个子树的根严格大于其左子树的所有元素,或者每个子树的根严格 少于其右子树的所有元素。这些弱属性无法Foldable实例或转换为列表的形式表示;他们必须直接检查。但是,您只需使用<=替换<,即可使用这些技术验证经典的BST属性。

关于空间的评论

包括这个在内的所有答案都有一些不幸的属性:给定一个非常重的树(例如Node (Node (...) 2 Leaf) 1 Leaf),他们将使用O(n)额外的空间来验证搜索树属性。有没有办法写这个,所以它不会有任何这样的坏案例?不幸的是,答案似乎是否定的。因此可以说明经典的BST属性:

  

每个节点必须大于其左子树的所有元素,并且少于其右子树的所有元素。

问题在于&#34;和&#34;。如果我们决定首先检查左子树,我们必须记住以便在之后检查正确的子树,反之亦然。

因此,唯一方式使验证更有效率是确保树是平衡的。