Quindi questo è in realtà un riferimento a un articolo di Meijer e alcuni altri chiamati " Programmazione funzionale con banane, obiettivi, buste e filo spinato ", l'idea di base è che possiamo prendere qualsiasi tipo di dati ricorsivo, come dire
data List = Cons Int List | Nil
e possiamo fattorizzare la ricorsione in una variabile di tipo
data ListF a = Cons Int a | Nil
il motivo per cui l'ho aggiunto F
è perché ora è un funzione! Ci consente anche di imitare gli elenchi, ma con una svolta: per creare elenchi dobbiamo nidificare il tipo di elenco
type ThreeList = ListF (ListF (ListF Void)))
Per recuperare la nostra lista originale dobbiamo continuare a nidificarla all'infinito . Questo ci darà un tipo ListFF
dove
ListF ListFF == ListFF
Per fare ciò, definire un "tipo a virgola fissa"
data Fix f = Fix {unfix :: f (Fix f)}
type ListFF = Fix ListF
Come esercizio, dovresti verificare che questo soddisfi la nostra equazione di cui sopra. Ora possiamo finalmente definire quali sono le banane (catamorfismi)!
type ListAlg a = ListF a -> a
ListAlg
s sono il tipo di "elenco algebre" e possiamo definire una particolare funzione
cata :: ListAlg a -> ListFF -> a
cata f = f . fmap (cata f) . unfix
Inoltre
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
Ti sembra familiare? cata
è esattamente lo stesso delle pieghe a destra!
La cosa veramente interessante è che possiamo farlo oltre a semplici elenchi, qualsiasi tipo definito con questo "punto fisso di un funzione" ha un cata
e per accontentarli tutto ciò che dobbiamo solo rilassare
cata :: (f a -> a) -> Fix f -> a
Questo è in realtà ispirato da un pezzo di teoria delle categorie che ho scritto su , ma questa è la carne del lato Haskell.