Haskell Language
Rekursionsschemata
Suche…
Bemerkungen
Funktionen, die hier in Beispielen erwähnt werden, sind in verschiedenen Paketen mit unterschiedlichen Abstraktionsgraden definiert, beispielsweise data-fix
und recursion-schemes
(hier mehr Funktionen). Sie können eine umfassendere Liste anzeigen, indem Sie mit Hayoo suchen .
Fixpunkte
Fix
nimmt einen "Vorlagen" -Typ und bindet den rekursiven Knoten, wobei die Vorlage wie eine Lasagne geschichtet wird.
newtype Fix f = Fix { unFix :: f (Fix f) }
In einem Fix f
finden wir eine Ebene der Vorlage f
. In füllen f
‚s - Parameter, Fix f
Stecker in sich. Wenn Sie also in die Vorlage f
schauen, finden Sie ein rekursives Vorkommen von Fix f
.
So kann ein typischer rekursiver Datentyp in unser Framework aus Vorlagen und Fixpunkten übersetzt werden. Wir entfernen rekursive Vorkommen des Typs und markieren ihre Positionen mit dem Parameter r
.
{-# LANGUAGE DeriveFunctor #-}
-- natural numbers
-- data Nat = Zero | Suc Nat
data NatF r = Zero_ | Suc_ r deriving Functor
type Nat = Fix NatF
zero :: Nat
zero = Fix Zero_
suc :: Nat -> Nat
suc n = Fix (Suc_ n)
-- lists: note the additional type parameter a
-- data List a = Nil | Cons a (List a)
data ListF a r = Nil_ | Cons_ a r deriving Functor
type List a = Fix (ListF a)
nil :: List a
nil = Fix Nil_
cons :: a -> List a -> List a
cons x xs = Fix (Cons_ x xs)
-- binary trees: note two recursive occurrences
-- data Tree a = Leaf | Node (Tree a) a (Tree a)
data TreeF a r = Leaf_ | Node_ r a r deriving Functor
type Tree a = Fix (TreeF a)
leaf :: Tree a
leaf = Fix Leaf_
node :: Tree a -> a -> Tree a -> Tree a
node l x r = Fix (Node_ l x r)
Schicht für Schicht eine Struktur zusammenfalten
Katamorphismen oder Falten modellieren die primitive Rekursion. cata
reißt ein Fixpunktes Schicht für Schicht nach unten, eine algebraischen Funktion (oder Faltungsfunktion) unter Verwendung von jeder Schicht zu verarbeiten. cata
erfordert eine Functor
Instanz für den Vorlagentyp f
.
cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = f . fmap (cata f) . unFix
-- list example
foldr :: (a -> b -> b) -> b -> List a -> b
foldr f z = cata alg
where alg Nil_ = z
alg (Cons_ x acc) = f x acc
Eine Schicht Schicht für Schicht entfalten
Anamorphismen modellieren primitive Corecursion oder entfalten sich . ana
baut einen Fixpunkt Schicht für Schicht auf und verwendet eine Coalgebra- Funktion (oder Entfaltungsfunktion ), um jede neue Ebene zu erzeugen. ana
erfordert eine Functor
Instanz für den Vorlagentyp f
.
ana :: Functor f => (a -> f a) -> a -> Fix f
ana f = Fix . fmap (ana f) . f
-- list example
unfoldr :: (b -> Maybe (a, b)) -> b -> List a
unfoldr f = ana coalg
where coalg x = case f x of
Nothing -> Nil_
Just (x, y) -> Cons_ x y
Beachten Sie, dass ana
und cata
dual sind . Die Typen und Implementierungen sind Spiegelbilder voneinander.
Entfalten und dann falten, verschmolzen
Es ist üblich, ein Programm so zu strukturieren, dass es eine Datenstruktur aufbaut und diese dann auf einen einzelnen Wert reduziert. Dies wird als Hylomorphismus oder Rückfaltung bezeichnet . Es ist möglich, die Zwischenstruktur insgesamt zu entfernen, um die Effizienz zu verbessern.
hylo :: Functor f => (a -> f a) -> (f b -> b) -> a -> b
hylo f g = g . fmap (hylo f g) . f -- no mention of Fix!
Ableitung:
hylo f g = cata g . ana f
= g . fmap (cata g) . unFix . Fix . fmap (ana f) . f -- definition of cata and ana
= g . fmap (cata g) . fmap (ana f) . f -- unfix . Fix = id
= g . fmap (cata g . ana f) . f -- Functor law
= g . fmap (hylo f g) . f -- definition of hylo
Primitive Rekursion
Paramorphismen modellieren primitive Rekursion. Bei jeder Wiederholung der Faltung erhält die Faltfunktion den Teilbaum zur weiteren Verarbeitung.
para :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a
para f = f . fmap (\x -> (x, para f x)) . unFix
Die tails
des Präludiums können als Paramorphismus modelliert werden.
tails :: List a -> List (List a)
tails = para alg
where alg Nil_ = cons nil nil -- [[]]
alg (Cons_ x (xs, xss)) = cons (cons x xs) xss -- (x:xs):xss
Primitive Kernflucht
Apomorphismen modellieren primitive Kernursachen. Bei jeder Wiederholung der Entfaltung kann die Entfaltungsfunktion entweder einen neuen Samen oder einen ganzen Unterbaum zurückgeben.
apo :: Functor f => (a -> f (Either (Fix f) a)) -> a -> Fix f
apo f = Fix . fmap (either id (apo f)) . f
Beachten Sie, dass apo
und para
dual sind . Die Pfeile im Typ werden umgedreht; das Tupel in para
zu dem Dual Either
in apo
, und die Implementierungen sind Spiegelbilder voneinander.