我强烈建议将Tree 更改为
data Tree a = Node (Tree a) a (Tree a)
| Leaf a
deriving (...)
并将在我的回答中使用它,但将其转换为您的 Tree 就像在任何地方设置 a ~ Int 并将 Tree Int 替换为 Tree 一样简单。
为每一层创建一个元素列表,然后检查所有这些元素是否已排序。假设你有一个函数
foldTree :: (a -> b) -> -- Leaf case
(b -> a -> b -> b) -> -- Node case
Tree a -> b
叶子产生一个列表,其中包含一个单例列表,后跟repeat [],因为叶子是一个级别上的单个元素,后跟无限多个空级别
leafCase x = [x] : repeat []
内部节点将子树的列表的子列表成对连接起来,同时还将它们的元素放在顶部的单例列表中:
nodeCase l x r = [x] : zipWith (++) l r
将其折叠在Tree 上以获得关卡列表,并在最后一个非空层之后将其切断:
levels = takeWhile (not . null) . foldTree leafCase nodeCase
检查每个级别是否已排序:
sorted = all (uncurry (<=)) . (zip <*> tail)
将所有功能组合成一个功能
sortedTree = all sorted . takeWhile (not . null) . levels
where sorted = all (uncurry (<=)) . (zip <*> tail)
levels = foldTree (\l -> [l] : repeat []) (\l x r -> [x] : zipWith (++) l r)
与recursion-schemes 相同:
makeBaseFunctor ''Tree
-- data TreeF a b = NodeF b a b | LeafF a
-- ...
levelsSorted :: (Recursive t, Foldable (Base t), Ord a) => (Base t [[a]] -> a) -> t -> Bool
levelsSorted get = all sorted . takeWhile (not . null) . levels
where sorted = all (uncurry (<=)) . (zip <*> tail)
levels = cata $ \x -> [get x] : foldr (zipWith (++)) (repeat []) x
levelsSortedTree :: Ord a => Tree a -> Bool
levelsSortedTree = levelsSorted $ \case { LeafF _ x _ -> x; NodeF x -> x }