Eine gute Möglichkeit, diese Codierung ist auf dem Traversal von Data.Foldable vorgesehen lehnen.
{-# LANGUAGE DeriveFunctor, DeriveFoldable #-}
import Data.Foldable
import Data.Monoid
Wir können eine Instanz davon ableiten automatisch eine Erweiterung verwenden, aber wir müssen die Felder der Knoten Konstruktor neu zu ordnen uns in Ordnung Traversal zu liefern.
Während wir gerade dabei sind, sollten wir die Beschränkungen für den Datentyp selbst beseitigen. Sie bieten tatsächlich keinen Nutzen, und hat sich von der Sprache ab Haskell 2011 entfernt worden ist (Wenn Sie solche Einschränkungen verwenden möchten, sollten Sie sie auf Instanzen von Klassen setzen, nicht auf den Datentyp.)
data BST a
= Void
| Node
{ left :: BST a
, val :: a
, right :: BST a
} deriving (Eq, Ord, Read, Show, Foldable)
Zuerst definieren wir , was es bedeutet , für eine Liste streng sortiert werden.
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.
Dann können wir die Verwendung toListMethode zur Verfügung gestellt Data.Foldableund die oben Helfer.
isBST :: Ord a => BST a -> Bool
isBST = sorted . toList
Wir können auch diese implementieren mehr direkt, wie Sie gefragt. Da wir die falschen Beschränkungen für den Datentyp entfernt, können wir die Definition Ihrer Falte vereinfachen.
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)
Jetzt brauchen wir einen Datentyp das Ergebnis unserer catamorphism zu modellieren, das ist , dass wir entweder keine Knoten ( Z) oder eine Reihe von streng monoton wachsend Knoten ( T) oder ausgefallen ist ( X)
data T a = Z | T a a | X deriving Eq
Und wir können dann implementieren isBSTdirekt
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
Das ist ein bisschen langweilig, vielleicht wäre es besser, den Weg zu zerlegen wir die Zwischenzustände ein wenig zusammensetzen:
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
Persönlich würde ich wahrscheinlich nur die faltbare Instanz.