Таким чином, це насправді посилання на документ Meijer та кілька інших під назвою " Функціональне програмування з бананами, лінзами, конвертами та колючим дротом ", основна ідея полягає в тому, що ми можемо приймати будь-який рекурсивний тип даних, як скажімо
data List = Cons Int List | Nil
і ми можемо визначити рекурсію на змінну типу
data ListF a = Cons Int a | Nil
Причина, чому я подав заяву, F
полягає в тому, що це зараз функтор! Це також дозволяє нам імітувати списки, але з поворотом: для створення списків ми повинні вкладати тип списку
type ThreeList = ListF (ListF (ListF Void)))
Щоб відновити наш початковий список, нам потрібно тримати це гніздування нескінченно . Це дасть нам тип ListFF
де
ListF ListFF == ListFF
Для цього визначте "тип фіксованої точки"
data Fix f = Fix {unfix :: f (Fix f)}
type ListFF = Fix ListF
Як вправу, ви повинні переконатися, що це задовольняє наше вище рівняння. Тепер ми можемо нарешті визначити, що таке банани (катаморфізми)!
type ListAlg a = ListF a -> a
ListAlg
s - тип "списку алгебр", і ми можемо визначити певну функцію
cata :: ListAlg a -> ListFF -> a
cata f = f . fmap (cata f) . unfix
Далі більше
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
Вигляд знайомий? cata
точно так само, як і праві складки!
Що насправді цікаво, це те, що ми можемо робити це більше, ніж просто списки, будь-який тип, який визначений цим "фіксованою точкою функтора", має, cata
і щоб вмістити їх усе, нам просто потрібно розслабити підпис типу
cata :: (f a -> a) -> Fix f -> a
Це насправді натхнене з фрагмента теорії категорій, про який я писав , але це м'ясо сторони Хаскелла.