En informática , la corecursión es un tipo de operación dual a la recursión (estructural) . Mientras que la recursión consume una estructura de datos manejando primero la capa superior antes de descender a sus partes internas, la corecursión produce una estructura de datos definiendo primero la capa superior antes de definir sus partes internas. La corecursión es particularmente importante en los lenguajes totales , ya que permite codificar computaciones potencialmente no terminantes en un contexto donde toda función debe terminar. Es compatible con los demostradores de teoremas Agda [ 1 ] y Rocq [ 2 ] .
Tanto la corecursión como la recursión pueden considerarse operaciones sobre árboles , que incluyen estructuras de datos.como listas y flujos como casos especiales. Dado que la recursión debe terminar, solo funciona en árboles que están bien fundados , es decir, que no son infinitamente profundos, que se llaman datos o tipos de datos iniciales ; por otro lado, la correcursión produce codatos o tipos de datos finales , que incluyen árboles infinitamente profundos. Los codatos no se pueden representar directamente en la memoria, por lo que a menudo se implementan usando estructuras de datos autorreferenciales o evaluación perezosa .
Datos y datos complementarios
En todos los lenguajes de programación, los números naturales se pueden definir de la siguiente manera (usando la sintaxis de Haskell [ a ] ):
datos Nat = Cero | Succ NatEsto establece que cada número natural es cero o el sucesor de un número natural existente. Por ejemplo, el número uno se representa como Succ Zero, el dos como Succ (Succ Zero), el tres como Succ (Succ (Succ Zero))y así sucesivamente.
Si interpretamos la declaración anterior de forma inductiva , entonces todos los números naturales se generan de esta manera, y obtenemos nuestro conjunto familiar de números naturales. Es importante destacar que podemos realizar recursión [ b ] en este conjunto: por ejemplo, podemos usarlo para crear una lista que repita un valor nveces:
repetir :: a -> Nat -> [ a ] repetir x Cero = [] -- Caso base repetir x ( Succ n ) = x : repetir x n -- Paso inductivoNótese que el uso de repeat x nes crucial: no podríamos haber escrito repeat x (Succ n), porque esa es la función que estamos tratando de definir, y por lo tanto, entraría en un bucle infinito. Más específicamente, la entrada debe hacerse más pequeña —o más bien más profunda, si se considera como una estructura de datos— cada vez que llamamos recursivamente.
La declaración también puede interpretarse de forma coinductiva , lo que puede denotarse como:
codata CoNat = Cero | Succ CoNatCoNattiene todos los números naturales que Nattiene automáticamente. Pero debido a que los codatos pueden ser infinitamente profundos, tiene un término adicional Succ (Succ (Succ (Succ …)))que continúa indefinidamente, a menudo denotado ∞. [ 3 ] Esto es único de los números conaturales, por lo que solo se puede construir usando la corecursión:
infinito :: CoNat infinito = Succ infinitoMientras que la recursión requiere que la entrada de la llamada recursiva sea cada vez menor, la correcursión requiere que la salida de la llamada recursiva sea cada vez mayor. Por eso debemos escribir Succ infinity; simplemente infinity = infinityno estaría permitido, ya que generaría un bucle infinito.
Para ilustrar la dualidad entre recursión y corecursión, podemos encapsularlas en dos funciones, recy corec. La existencia de estas funciones, junto con los dos constructores regulares de Naty CoNat, identifican de forma única sus respectivos tipos y, por lo tanto, permiten reescribir todas las formas de recursión y corecursión en términos de ellas. [ 4 ]
rec :: Nat -> ( Quizás c -> c ) -> c rec Cero f = f Nada rec ( Succ n ) f = f ( Solo ( rec n f ))corec :: ( c -> Quizás c ) -> c -> CoNat corec f base = caso f base de Nada -> Cero Solo x -> Succ ( corec f x )Conceptualmente, CoNatpuede pensarse como una máquina de estados , donde ces un tipo que encapsula el "estado actual". La función c -> Maybe ces una función de transición de estado que resulta en la terminación con Zeroo la continuación con Succ. Podemos reescribir los ejemplos anteriores usando las funciones:
repetir x n = rec n ( \ s -> caso s de Nothing -> [] Just a -> x : a ) infinito = corec ( \ () -> Just () ) ()Un ejemplo más complejo de codata es el de los árboles binarios , donde cada nodo es un nodo hoja, que contiene algunos datos, o es un nodo rama que tiene exactamente dos hijos:
codata BinaryTree a = Hoja a | Rama ( BinaryTree a ) ( BinaryTree a )Este ejemplo tiene muchos más términos infinitamente profundos que solo se pueden construir mediante correcursión. Por ejemplo, puede ser infinitamente profundo solo en el lado izquierdo, o en ambos lados, o alternando izquierda y derecha:
infiniteLeft :: a -> BinaryTree a infiniteLeft x = Branch ( infiniteLeft x ) ( Leaf x )infiniteBoth :: BinaryTree a infiniteBoth = Branch infiniteBoth infiniteBothinfiniteAlternating :: a -> Bool -> BinaryTree a infiniteAlternating x False = Branch ( infiniteAlternating x True ) ( Leaf x ) infiniteAlternating x True = Branch ( Leaf x ) ( infiniteAlternating x False )Nuevamente, la correcursión en árboles binarios tiene una forma más general basada en un constructor tipo "máquina de estados":
corec :: ( c -> Either a ( c , c )) -> c -> BinaryTree a corec f base = case f base of Left x -> Leaf x Right ( x , y ) -> Branch ( corec f x ) ( corec f y )Tipos M
En un entorno de tipos dependientes , los codatos se pueden codificar utilizando tipos M, que son duales a los tipos W. Dado un tipo A y una familia de tipos B indexada por A , se puede formar el tipo M., que representan el tipo de árboles cuyos nodos están etiquetados con elementos de A y cuyos nodos hijos están indexados por el conjunto B ( a ). En pseudocódigo , los tipos M (y su principio de correcursión) pueden definirse como:
codata M a ( b :: a -> * ) = M { raíz :: a , rama :: b raíz -> M a b } corec :: ( c -> ( raíz :: a , b raíz -> c )) -> c -> M a b corec f base = let ( raíz , rama ) = f base in M { raíz = raíz , rama = \ i -> corec f ( rama i ) }Como ejemplo, los números naturales y conaturales pueden construirse como tipos W y M de la misma función:
f :: Bool -> * f False = Void -- Caso cero (sin ramificaciones) f True = () -- Caso exitoso (una ramificación)Nat = W Bool f CoNat = M Bool fSe puede demostrar que los tipos M existen en muchos topoi elementales , y su existencia se deriva de la existencia de los tipos W. [ 5 ]
Descripción matemática
La sección anterior mostró que existe un vínculo íntimo entre los números naturales y conaturales y Maybe c, y de manera similar entre los árboles binarios y Either a (c, c). Este vínculo se precisa al mostrar que Natestá en biyección con Maybe Naty CoNatcon Maybe CoNat; explícitamente, esta biyección se asocia Zerocon Nothingy Succ ncon Just n. En otras palabras, Naty CoNatson puntos fijos ( salvo isomorfismo ) del mapa.
La diferencia entre datos y codatos radica en que los datos representan el menor número de puntos fijos, mientras que los codatos representan el mayor. De esta manera, la recursión puede resumirse como la afirmación de que "cada elemento del tipo fue generado únicamente por los constructores dados ( Zeroy Succen el caso de Nat/ CoNat)", mientras que la correcursión afirma que "existe cada valor que puede ser analizado utilizando los constructores como casos".
Desde una perspectiva de teoría de categorías, CoNatpuede definirse con precisión como la coalgebra final del endofunctor.. [ 4 ] Desarrollando esta definición, tenemos que:
- Hay una función . "Pred" significa "predecesor", y la intuición es que resta uno al número conatural o da otro resultado. En otras palabras, y . Esto muestra que es una coálgebra del functor, pero no necesariamente la final.
pred :: CoNat -> Maybe CoNatNothingpred Zero = Nothingpred (Succ n) = Just nCoNat - Para cada tipo
cy función , existe una función tal que . Desglosando esto aún más, si entonces , mientras que si entonces —esto coincide con la definición de con la que estamos familiarizados.f :: c -> Maybe ccorec f :: c -> CoNatpred (corec f x) = fmap (corec f) (f x)f x = Just ycorec f x = Succ (corec f y)f x = Nothingcorec f x = Zerocorec coreces único en el siguiente sentido: para cualquier otra función que también satisfaga , . Esto garantiza que sea una coálgebra final .g :: c -> CoNatpred (g x) = fmap g (f x)g x = corec f xCoNat
Maybe cpuede reemplazarse con cualquier otro functor en la descripción anterior para obtener la definición de cualquier otro tipo coinductivo.
No todos los functores tienen coálgebras finales. Por ejemplo, el teorema de Cantor nos dice que ningún conjunto puede estar en biyección con su conjunto potencia, y por lo tanto el functor del conjunto potenciaa -> Bool no tiene coálgebra final. Sin embargo, en el caso de los functores polinomiales o los functores polinomiales cociente [ 6 ] , siempre existen coálgebras finales; los functores polinomiales son functores que pueden expresarse en la formapara una familia de tipos α y α -indexada β ( a ). El tipo M es exactamente la construcción de esta coálgebra final. [ 5 ]
Coinducción
Si bien se puede razonar sobre los tipos de datos coinductivos utilizando la unicidad de corecdirectamente, a menudo es más conveniente usar la coinducción , que puede probar igualdades de codata. Dado un coálgebra final A de un functor polinomial F —es decir— decimos que una relaciónes una bisimulación si, para todo,ya pesar de. Aquí,yConsulte los mapas:
El principio de coinducción establece que para todas las bisimulaciones R en A y,.
De forma más general, para un mapa de coalgebra, una relación R en A es una bisimulación si existe una funciónSatisfactorio para todos.,
- y
- ,
donde π ₁ y π ₂ son los mapas de primera y segunda proyección.. Esto puede verse como equivalente al caso polinómico al establecerLas igualdades requeridas también pueden expresarse como un diagrama conmutativo:
![]()
La coinducción es fácil de demostrar a partir de la unicidad de corec: π ₁ y π ₂ satisfacen la propiedad requerida de ser iguales a corec f, y por lo tanto son iguales entre sí, demostrando así que. [ 4 ]
Ejemplo: Suma de números conaturales
Para demostrar el uso de la coinducción, probaremos algunas propiedades básicas sobre la suma en números conaturales. La suma se puede definir de forma idéntica a como se define para los números naturales: [ 3 ]
agregar :: CoNat -> CoNat -> CoNat agregar a Cero = a agregar a ( Succ b ) = Succ ( agregar a b )Esta definición, si bien es válida, oculta cierta complejidad. Alternativamente, podemos escribir:
agregar cero Cero = Cero agregar ( Succ a ) Cero = Succ ( agregar un cero ) agregar a ( Succ b ) = Succ ( agregar un b )Esta definición hace que la traducción sea corecsencilla:
iterar :: ( CoNat , CoNat ) -> Quizás ( CoNat , CoNat ) iterar Cero Cero = Nada iterar ( Succ a ) Cero = Just ( a , Cero ) iterar a ( Succ b ) = Just ( a , b )agregar a b = corec iterar ( a , b )Podemos demostrar quepor coinducción en la relación(dóndees el conjunto de los números conaturales). Primero, de la definición de suma se deduce que; segundo, si asumimos quees de la formapara algún a , debemos demostrar queTambién es de esta forma. Tenemos:De este modoy por lo tantosegún sea necesario.
La identidadpuede probarse de manera similar mediante coinducción en(recuerde que la relación debe necesariamente incluir); finalmente, la conmutatividad——resultados de coinducción directa similar en. [ 7 ]
En lenguajes de programación
Si el dominio del discurso es la categoría de conjuntos y funciones totales (como en demostradores de teoremas como Agda y Rocq), entonces los tipos finales (codatos) pueden contener valores infinitos no bien fundados , mientras que los tipos iniciales (datos) no. [ 8 ] [ 9 ] Por otro lado, si el dominio del discurso es la categoría de órdenes parciales completos y funciones continuas , que corresponde aproximadamente al lenguaje de programación Haskell , entonces los tipos finales coinciden con los tipos iniciales, y la coálgebra final y el álgebra inicial correspondientes forman un isomorfismo. [ 10 ]
Historia
La corecursión, también conocida como programación circular, se remonta al menos a ( Bird 1984 ) , quien atribuye su desarrollo a John Hughes y Philip Wadler ; formas más generales se desarrollaron en ( Allison 1989 ) . Las motivaciones originales incluían la creación de algoritmos más eficientes (que permitían una sola pasada sobre los datos en algunos casos, en lugar de requerir múltiples pasadas) y la implementación de estructuras de datos clásicas, como listas doblemente enlazadas y colas, en lenguajes funcionales.
Véase también
Notas
- ↑ Haskell, al ser un lenguaje parcial y perezoso, no admite ni datos ni codatos; utilizamos su sintaxis por familiaridad.
- ↑ Aquí, "recursión" se usa en el sentido técnico de recursión estructural , que es un tipo de recursión que analiza la estructura de un tipo y siempre termina. En el sentido más general del término utilizado en informática, la corecursión también es un tipo de recursión.
Referencias
- ↑ Autores de Agda. "Coinducción" . Documentación de Agda 2.8.0 . Archivado del original el 18 de febrero de 2026. Consultado el 13 de marzo de 2026 .
- ↑ Inria, CNRS y colaboradores. "Tipos coinductivos y funciones corecursivas" . Documentación de Rocq Prover 9.1.0 . Consultado el 13 de marzo de 2026 .
- 1 2 Xie, Szumi; Bense, Viktor (2025-10-09). "Los números conaturales forman un semianillo conmutativo exponencial" . Actas del 10.º Taller Internacional ACM SIGPLAN sobre Desarrollo Dirigido por Tipos . TyDe '25. Nueva York, NY, EE. UU.: Association for Computing Machinery. págs. 52–63 . doi : 10.1145/3759538.3759654 . ISBN 979-8-4007-2163-2.
- 1 2 3 Jacobs, Bart; Rutten, Jan (2011), "Una introducción al (co)álgebra y la (co)inducción", en Sangiorgi, Davide; Rutten, Jan (eds.), Temas avanzados en bisimulación y coinducción , Cambridge Tracts in Theoretical Computer Science, Cambridge: Cambridge University Press, pp. 38–99 , doi : 10.1017/CBO9780511792588.003 , ISBN 978-1-107-00497-9, consultado el 14 de marzo de 2026
- 1 2 van den Berg, Benno; De Marchi, Federico (2007-04-01). "Árboles no bien fundados en categorías" . Annals of Pure and Applied Logic . 146 (1): 40– 59. doi : 10.1016/j.apal.2006.12.001 . ISSN 0168-0072 .
- ^ Avigad, Jeremy; Carneiro, Mario; Hudon, Simón (2019). Harrison, Juan; O'Leary, John; Tolmach, Andrew (eds.). "Tipos de datos como cocientes de funtores polinomiales" . Lipics, Volumen 141, Itp 2019 . Procedimientos internacionales de informática de Leibniz (LIPIcs). 141 . Dagstuhl, Alemania: Schloss Dagstuhl – Leibniz-Zentrum für Informatik: 6:1–6:19. doi : 10.4230/LIPIcs.ITP.2019.6 . ISBN 978-3-95977-122-1.
- ↑ Rutten, JJMM (2000-10-17). "Acogebra universal: una teoría de sistemas" . Theoretical Computer Science . Modern Algebra. 249 (1): 3– 80. doi : 10.1016/S0304-3975(00)00056-6 . ISSN 0304-3975 .
- ↑ Barwise y Moss 1996.
- ↑ Moss y Danner 1997.
- ↑ Smyth y Plotkin 1982.
- Bird, Richard Simpson (1984). "Uso de programas circulares para eliminar múltiples recorridos de datos". Acta Informatica . 21 (3): 239– 250. doi : 10.1007/BF00264249 . S2CID 27392591 .
- Allison, Lloyd (abril de 1989). "Programas circulares y estructuras autorreferenciales" . Software: Practice and Experience . 19 (2): 99– 109. arXiv : 2403.01866 . doi : 10.1002/spe.4380190202 . S2CID 21298473 .
- Geraint Jones y Jeremy Gibbons (1992). Algoritmos de árboles en amplitud de tiempo lineal: Un ejercicio de aritmética de pliegues y cremalleras (Informe técnico). Departamento de Ciencias de la Computación, Universidad de Auckland.
- Jon Barwise ; Lawrence S. Moss (junio de 1996). Círculos viciosos . Centro para el Estudio del Lenguaje y la Información. ISBN 978-1-57586-009-1Archivado del original el 21/06/2010 . Consultado el 24/01/2011 .
- Lawrence S. Moss; Norman Danner (1997). "Sobre los fundamentos de la corecursion". Logic Journal of the IGPL . 5 (2): 231– 257. CiteSeerX 10.1.1.40.4243 . doi : 10.1093/jigpal/5.2.231 .
- Kees Doets; Jan van Eijck (mayo de 2004). El camino de Haskell hacia la lógica, las matemáticas y la programación . Publicaciones de King's College. ISBN 978-0-9543006-9-2.
- David Turner (28 de julio de 2004). "Programación funcional total" . Journal of Universal Computer Science . 10 (7): 751– 768. doi : 10.3217/jucs-010-07-0751 .
- Jeremy Gibbons; Graham Hutton (abril de 2005). "Métodos de prueba para programas correcursivos" . Fundamenta Informaticae . 66 (4): 353–366 .
- Leon P. Smith (29 de julio de 2009), "Las colas corecursivas de Lloyd Allison: por qué importan las continuaciones" , The Monad Reader ( 14): 37–68
- Raymond Hettinger (19 de noviembre de 2009). "Receta 576961: Técnica para la iteración cíclica" .
- MB Smyth y GD Plotkin (1982). "La solución teórica de categorías de ecuaciones de dominio recursivas" (PDF) . SIAM Journal on Computing . 11 (4): 761– 783. doi : 10.1137/0211062 . S2CID 8517995 .
- Leclerc, Francois; Paulin-Mohring, Christine (1993). Programación con flujos en Coq: un estudio de caso: la criba de Eratóstenes . Types for Proofs and Programs: International Workshop TYPES '93. Springer-Verlag New York, Inc. pp. 191–212 . ISBN 978-3-540-58085-0.
- informática teórica
- Autorreferencia
- Programación funcional
- Teoría de categorías
- Recursión