Ένας ωραίος τρόπος για να κωδικοποιούν αυτό είναι να σκύψει πάνω στο διάσχιση παρέχονται από Data.Foldable.
{-# LANGUAGE DeriveFunctor, DeriveFoldable #-}
import Data.Foldable
import Data.Monoid
Μπορούμε να αντλήσει ένα παράδειγμα από αυτό αυτόματα χρησιμοποιώντας μια επέκταση, αλλά πρέπει να αναδιατάξετε τα πεδία του κατασκευαστή Κόμβος για να μας παρέχουν μια διάσχιση στην παραγγελία.
Ενώ είμαστε σε αυτό, θα πρέπει να εξαλείψει τους περιορισμούς σχετικά με το ίδιο το είδος των δεδομένων. Στην πραγματικότητα παρέχει κανένα όφελος, και έχει αφαιρεθεί από τη γλώσσα, όπως της Haskell 2011. (Όταν θέλετε να χρησιμοποιήσετε, όπως οι περιορισμοί θα πρέπει να τους θέσει σε περιπτώσεις τάξεις, όχι για τον τύπο δεδομένων.)
data BST a
= Void
| Node
{ left :: BST a
, val :: a
, right :: BST a
} deriving (Eq, Ord, Read, Show, Foldable)
Πρώτα ορίζουμε τι σημαίνει για μια λίστα που θα ταξινομηθούν αυστηρά.
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.
Στη συνέχεια, μπορούμε να χρησιμοποιήσουμε τη toListμέθοδο που προβλέπεται από Data.Foldableκαι παραπάνω βοηθός.
isBST :: Ord a => BST a -> Bool
isBST = sorted . toList
Μπορούμε επίσης να εφαρμόσει αυτό το πιο άμεσα, όπως σας ζητηθεί. Από τη στιγμή που απομακρύνονται τα πλαστά περιορισμούς σχετικά με το είδος των δεδομένων, μπορούμε να απλοποιήσουμε τον ορισμό των φορές σας.
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)
Τώρα χρειαζόμαστε έναν τύπο δεδομένων για να διαμορφώσει το αποτέλεσμα της catamorphism μας, η οποία είναι ότι έχουμε είτε δεν κόμβους ( Z), ή μια σειρά από αυστηρά αύξηση κόμβων ( T) ή έχουν αποτύχει ( X)
data T a = Z | T a a | X deriving Eq
Και μπορεί στη συνέχεια να εφαρμόσουν isBSTάμεσα
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
Αυτό είναι λίγο κουραστική, οπότε ίσως θα ήταν καλύτερα να αποσυνθέσει τον τρόπο που συνθέτουν την ενδιάμεση αναφέρει ένα κομμάτι:
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
Προσωπικά, θα ήθελα ίσως απλά χρησιμοποιήστε το πτυσσόμενο παράδειγμα.