En lisant cet article classique , je suis coincé sur les paramorphismes. Malheureusement, la section est assez mince et la page Wikipédia ne dit rien.
Ma traduction Haskell est:
para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f base = h
where
h [] = base
h (x:xs) = f x xs (h xs)
Mais je ne gémis pas - je n'ai aucune intuition pour la signature de type ou le résultat souhaité.
Qu'est-ce qu'un paramorphisme et quels sont quelques exemples utiles en action?
Oui, j'ai vu ces questions , mais elles ne couvrent pas directement les paramorphismes et ne désignent que des ressources qui peuvent être utiles comme références, mais pas comme supports d'apprentissage.
para f base xs = foldr (uncurry f) base $ zip xs (tail $tails xs)
, il me semble.para f base xs = foldr g base (init $ tails xs) where g (x:xs) = f x xs
. Cela rappelle Common Lispmaplist
.Réponses:
Oui c'est ça
para
. Comparez avec le catamorphisme, oufoldr
:Certaines personnes appellent les paramorphismes «récursion primitive» par opposition aux catamorphismes (
foldr
) étant «itération».Où
foldr
les deux paramètres reçoivent une valeur calculée de manière récursive pour chaque sous-objet récursif des données d'entrée (ici, c'est la queue de la liste),para
les paramètres de s obtiennent à la fois le sous-objet d'origine et la valeur calculée de manière récursive à partir de celui-ci.Un exemple de fonction qui est joliment exprimé avec
para
est la collection des suffisants appropriés d'une liste.pour que
Peut-être encore plus simple est-il
dans lequel la branche "cons" ignore son argument récursivement calculé et rend juste la queue. Evalué paresseusement, le calcul récursif ne se produit jamais et la queue est extraite en temps constant.
Vous pouvez définir en
foldr
utilisantpara
assez facilement; il est un peu plus délicat à définir àpara
partirfoldr
, mais il est certainement possible, et tout le monde devrait savoir comment faire!L'astuce pour définir
para
avecfoldr
est de reconstruire une copie des données originales, de sorte que nous ayons accès à une copie de la queue à chaque étape, même si nous n'avions pas accès à l'original. À la fin,snd
supprime la copie de l'entrée et donne juste la valeur de sortie. Ce n'est pas très efficace, mais si vous êtes intéressé par l'expressivité pure,para
ne vous en donne pas plusfoldr
. Si vous utilisez cettefoldr
version codée depara
,safeTail
cela prendra un temps linéaire après tout, la copie de la queue élément par élément.Alors, c'est tout:
para
c'est une version plus pratiquefoldr
qui vous donne un accès immédiat à la queue de la liste ainsi qu'à la valeur calculée à partir de celle-ci.Dans le cas général, travailler avec un type de données généré comme point fixe récursif d'un foncteur
vous avez
et encore une fois, les deux sont mutuellement définissables, avec
para
définis à partircata
de la même astuce "faire une copie"Encore une fois, ce
para
n'est pas plus expressif quecata
, mais plus pratique si vous avez besoin d'un accès facile aux sous-structures de l'entrée.Edit: Je me suis souvenu d'un autre bel exemple.
Considérons les arbres de recherche binaires donnés par
Fix TreeF
oùet essayez de définir l'insertion pour les arbres de recherche binaires, d'abord comme a
cata
, puis comme apara
. Vous trouverez lapara
version beaucoup plus facile, car à chaque nœud, vous devrez insérer dans un sous-arbre mais conserver l'autre tel qu'il était.la source