Portanto, na verdade, isso é referenciado por um artigo de Meijer e alguns outros chamados " Programação Funcional com Bananas, Lentes, Envelopes e Arame Farpado ", a idéia básica é que podemos usar qualquer tipo de dados recursivos, como, por exemplo,
data List = Cons Int List | Nil
e podemos fatorar a recursão em uma variável de tipo
data ListF a = Cons Int a | Nil
a razão pela qual eu anexei isso F
é porque agora é um functor! Também nos permite imitar listas, mas com um toque: para criar listas, precisamos aninhar o tipo de lista
type ThreeList = ListF (ListF (ListF Void)))
Para recuperar nossa lista original, precisamos continuar aninhando isso infinitamente . Isso nos dará um tipo ListFF
em que
ListF ListFF == ListFF
Para isso, defina um "tipo de ponto fixo"
data Fix f = Fix {unfix :: f (Fix f)}
type ListFF = Fix ListF
Como exercício, você deve verificar se isso satisfaz a equação acima. Agora podemos finalmente definir o que são bananas (catamorfismos)!
type ListAlg a = ListF a -> a
ListAlg
s são o tipo de "lista de álgebras" e podemos definir uma função específica
cata :: ListAlg a -> ListFF -> a
cata f = f . fmap (cata f) . unfix
Além disso
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
Parece familiar? cata
é exatamente o mesmo que dobras à direita!
O que é realmente interessante é que podemos fazer isso mais do que apenas listas, qualquer tipo definido com esse "ponto fixo de um functor" possui um cata
e, para acomodá-los, basta relaxar a assinatura de tipo
cata :: (f a -> a) -> Fix f -> a
Na verdade, isso é inspirado em uma parte da teoria das categorias sobre a qual escrevi , mas essa é a carne do lado Haskell.