Jest to dobry sposób kodowania jest oprzeć się na przechodzenie dostarczonych przez Data.Foldable.
{-# LANGUAGE DeriveFunctor, DeriveFoldable #-}
import Data.Foldable
import Data.Monoid
Możemy czerpać wystąpienie to automatycznie za pomocą rozszerzenia, ale musimy zmienić kolejność pól konstruktora węzła do zapewnienia nam przechodzenie na zamówienie.
Chociaż już przy tym jesteśmy, powinniśmy wyeliminować ograniczenia dotyczące samego typu danych. Oni rzeczywiście nie daje żadnych korzyści, a została usunięta z języka począwszy od Haskell 2011 roku (kiedy chcesz używać takich ograniczeń należy umieścić je na instancje klas, a nie od typu danych.)
data BST a
= Void
| Node
{ left :: BST a
, val :: a
, right :: BST a
} deriving (Eq, Ord, Read, Show, Foldable)
Najpierw musimy zdefiniować, co to znaczy dla lista być ściśle sortowane.
sorted :: Ord a => [a] -> Bool
sorted [] = True
sorted [x] = True
sorted (x:xs) = x < head xs && sorted xs
-- head is safe because of the preceeding match.
Wtedy możemy użyć toListmetody zalecanej przez Data.Foldablei powyższy pomocnika.
isBST :: Ord a => BST a -> Bool
isBST = sorted . toList
Możemy również zaimplementować to w bardziej bezpośredni sposób, jak prosiłeś. Ponieważ usunięte fałszywe ograniczenia na typ danych, możemy uprościć definicję swojej owczarni.
cata :: (b -> a -> b -> b) -> b -> BST a -> b
cata _ z Void = z
cata f z (Node l x r) = f (cata f z l) x (cata f z r)
Teraz musimy typ danych do modelowania wynik naszej catamorphism, co jest, że nie mamy jeszcze węzły ( Z) lub szeregu ściśle rosnących węzłów ( T) lub nie udało ( X)
data T a = Z | T a a | X deriving Eq
I możemy następnie wdrożyć isBSTbezpośrednio
isBST' :: Ord a => BST a -> Bool
isBST' b = cata phi Z b /= X where
phi X _ _ = X
phi _ _ X = X
phi Z a Z = T a a
phi Z a (T b c) = if a < b then T a c else X
phi (T a b) c Z = if b < c then T a c else X
phi (T a b) c (T d e) = if b < c && c < d then T a e else X
To jest trochę uciążliwe, więc może lepiej byłoby, aby rozłożyć nasz sposób skomponować stanach Interim kawałek:
cons :: Ord a => a -> T a -> T a
cons _ X = X
cons a Z = T a a
cons a (T b c) = if a < b then T a c else X
instance Ord a => Monoid (T a) where
mempty = Z
Z `mappend` a = a
a `mappend` Z = a
X `mappend` _ = X
_ `mappend` X = X
T a b `mappend` T c d = if b < c then T a d else X
isBST'' :: Ord a => BST a -> Bool
isBST'' b = cata phi Z b /= X where
phi l a r = l `mappend` cons a r
Osobiście pewnie wystarczy użyć Składany instancji.