Dies ist also ein Verweis auf einen Artikel von Meijer und einigen anderen mit dem Titel " Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire ". Die Grundidee ist, dass wir jeden rekursiven Datentyp annehmen können, wie zum Beispiel
data List = Cons Int List | Nil
und wir können die Rekursion in eine Typvariable ausklammern
data ListF a = Cons Int a | Nil
Der Grund, warum ich das angehängt habe, F
ist, dass dies jetzt ein Funktor ist! Es erlaubt uns auch, Listen zu imitieren, aber mit einem Twist: Um Listen zu erstellen, müssen wir den Listentyp verschachteln
type ThreeList = ListF (ListF (ListF Void)))
Um unsere ursprüngliche Liste wiederherzustellen, müssen wir diese unendlich verschachteln . Das wird uns einen Typ geben, ListFF
wo
ListF ListFF == ListFF
Dazu definieren Sie einen "Fixpunkttyp"
data Fix f = Fix {unfix :: f (Fix f)}
type ListFF = Fix ListF
Als Übung sollten Sie überprüfen, ob dies unserer obigen Gleichung entspricht. Jetzt können wir endlich definieren, was Bananen (Katamorphismen) sind!
type ListAlg a = ListF a -> a
ListAlg
s ist der Typ von "Listenalgebren", und wir können eine bestimmte Funktion definieren
cata :: ListAlg a -> ListFF -> a
cata f = f . fmap (cata f) . unfix
Außerdem
cata :: ListAlg a -> ListFF -> a
cata :: (Either () (Int, a) -> a) -> ListFF -> a
cata :: (() -> a) -> ((Int, a) -> a) -> ListFF -> a
cata :: a -> (Int -> a -> a) -> ListFF -> a
cata :: (Int -> a -> a) -> a -> [Int] -> a
Ähnlich aussehend? cata
ist genau das gleiche wie rechts falten!
Was wirklich interessant ist, ist, dass wir dies über mehr als nur Listen hinweg tun können. Jeder Typ, der mit diesem "Fixpunkt eines Funktors" definiert ist, hat ein cata
und um sie zu berücksichtigen, müssen wir nur die Typensignatur lockern
cata :: (f a -> a) -> Fix f -> a
Dies ist eigentlich inspiriert von einem Stück Kategorietheorie, über das ich geschrieben habe , aber dies ist das Fleisch der Haskell-Seite.