Lendo este artigo clássico , estou preso em paramorfismos. Infelizmente, a seção é bem estreita e a página da Wikipedia não diz nada.
Minha tradução de Haskell é:
para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f base = h
where
h [] = base
h (x:xs) = f x xs (h xs)
Mas eu não groco isso - não tenho nenhuma intuição para a assinatura de tipo ou o resultado desejado.
O que é um paramorfismo e quais são alguns exemplos úteis em ação?
Sim, eu vi essas perguntas , mas elas não cobrem os paramorfismos diretamente e apenas apontam para recursos que podem ser úteis como referências, mas não como materiais de aprendizagem.
haskell
recursion
functional-programming
higher-order-functions
Matt Fenwick
fonte
fonte
para f base xs = foldr (uncurry f) base $ zip xs (tail $tails xs)
, penso eu.para f base xs = foldr g base (init $ tails xs) where g (x:xs) = f x xs
. Isso lembra o Common Lispmaplist
.Respostas:
Sim, é isso
para
. Compare com catamorfismo oufoldr
:Algumas pessoas chamam os paramorfismos de "recursão primitiva" em contraste com os catamorfismos (
foldr
) sendo "iteração".Onde
foldr
's dois parâmetros recebem um valor calculado recursivamente para cada subobjeto recursivo dos dados de entrada (aqui, esse é o fim da lista),para
os parâmetros' s obtêm o subobjeto original e o valor calculado recursivamente a partir dele.Um exemplo de função que é bem expresso
para
é a coleção dos elementos adequados de uma lista.de modo a
Possivelmente mais simples ainda é
em que o ramo "contras" ignora seu argumento calculado recursivamente e apenas retorna a cauda. Avaliado preguiçosamente, o cálculo recursivo nunca acontece e a cauda é extraída em tempo constante.
Você pode definir
foldr
usando compara
bastante facilidade; é um pouco mais complicado para definirpara
a partirfoldr
, mas é certamente possível, e todos devem saber como se faz!O truque para definir
para
comfoldr
é reconstruir uma cópia dos dados originais, de modo que tenhamos acesso a uma cópia da cauda em cada etapa, mesmo que não tenhamos acesso ao original. Ao final,snd
descarta a cópia da entrada e dá apenas o valor de saída. Não é muito eficiente, mas se você está interessado em expressividade pura, nãopara
oferece mais do quefoldr
. Se você usar estafoldr
versão codificada depara
, entãosafeTail
levará um tempo linear, copiando a cauda elemento por elemento.Então, é isso:
para
é uma versão mais conveniente dofoldr
que lhe dá acesso imediato ao final da lista, bem como ao valor calculado a partir dela.No caso geral, trabalhar com um tipo de dados gerado como o ponto de fixação recursivo de um functor
Você tem
e, novamente, os dois são mutuamente definíveis, sendo
para
definidoscata
pelo mesmo truque de "fazer uma cópia"Novamente,
para
não é mais expressivo do quecata
, mas mais conveniente se você precisar de acesso fácil às subestruturas da entrada.Edit: Lembrei-me de outro bom exemplo.
Considere as árvores de pesquisa binárias fornecidas por
Fix TreeF
ondee tente definir a inserção para árvores de pesquisa binárias, primeiro como a
cata
, depois como apara
. Você achará apara
versão muito mais fácil, já que em cada nó você precisará inserir em uma subárvore, mas preservar a outra como estava.fonte