Al leer este artículo clásico , estoy atrapado en paramorfismos. Desafortunadamente, la sección es bastante delgada y la página de Wikipedia no dice nada.
Mi traducción de Haskell es:
para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f base = h
where
h [] = base
h (x:xs) = f x xs (h xs)
Pero no asimilo eso, no tengo ninguna intuición para la firma tipográfica o el resultado deseado.
¿Qué es un paramorfismo y cuáles son algunos ejemplos útiles en acción?
Sí, he visto estas preguntas , pero no cubren los paramorfismos directamente y solo apuntan a recursos que pueden ser útiles como referencias, pero no como materiales de aprendizaje.
haskell
recursion
functional-programming
higher-order-functions
Matt Fenwick
fuente
fuente
para f base xs = foldr (uncurry f) base $ zip xs (tail $tails xs)
, me parece.para f base xs = foldr g base (init $ tails xs) where g (x:xs) = f x xs
. Esto recuerda a Common Lispmaplist
.Respuestas:
Sí, eso es
para
. Compare con catamorfismo, ofoldr
:Algunas personas llaman a los paramorfismos "recursividad primitiva" en contraste con los catamorfismos (
foldr
) que son "iteración".Donde
foldr
los dos parámetros reciben un valor calculado de forma recursiva para cada subobjeto recursivo de los datos de entrada (aquí, esa es la cola de la lista),para
los parámetros obtienen tanto el subobjeto original como el valor calculado de forma recursiva a partir de él.Una función de ejemplo que se expresa muy bien con
para
es la colección de los suficientes suficientes de una lista.así que eso
Posiblemente más simple aún es
en el que la rama "contras" ignora su argumento calculado de forma recursiva y simplemente devuelve la cola. Evaluado con pereza, el cálculo recursivo nunca ocurre y la cola se extrae en tiempo constante.
Puede definir
foldr
usandopara
bastante facilidad; que es un poco más difícil de definirpara
a partirfoldr
, pero es ciertamente posible, y todo el mundo debe saber cómo se hace!El truco para definir
para
confoldr
es reconstruir una copia de los datos originales, de modo que obtengamos acceso a una copia de la cola en cada paso, aunque no tuviéramos acceso al original. Al final,snd
descarta la copia de la entrada y da solo el valor de salida. No es muy eficiente, pero si te interesa la expresividad pura,para
no te da más quefoldr
. Si usa estafoldr
versión codificada depara
, luegosafeTail
tomará un tiempo lineal después de todo, copiando la cola elemento por elemento.Entonces, eso es todo:
para
es una versión más conveniente de lafoldr
cual le brinda acceso inmediato al final de la lista, así como al valor calculado a partir de ella.En el caso general, trabajar con un tipo de datos generado como el punto fijo recursivo de un funtor
tienes
y de nuevo, los dos son mutuamente definibles,
para
definidoscata
por el mismo truco "hacer una copia"De nuevo,
para
no es más expresivocata
, pero es más conveniente si necesita un fácil acceso a las subestructuras de la entrada.Editar: Recordé otro buen ejemplo.
Considere los árboles de búsqueda binarios dados por
Fix TreeF
dondee intente definir la inserción para árboles de búsqueda binarios, primero como a
cata
, luego como apara
. Encontrará lapara
versión mucho más fácil, ya que en cada nodo deberá insertar un subárbol pero conservar el otro tal como estaba.fuente