¿Qué lenguajes de programación imperativos no admiten la recursividad?

21

Que yo sepa, todos los lenguajes de programación imperativos modernos admiten la recursión en el sentido de que un procedimiento puede llamarse a sí mismo. Este no siempre fue el caso, pero no puedo encontrar ningún dato difícil con una búsqueda rápida en Google. Entonces mi pregunta es:

¿Qué idiomas no admitieron la recursividad desde el principio y cuándo se agregó ese soporte?

flujo libre
fuente

Respuestas:

21

No estoy seguro de que COBOL lo haga (ciertamente no lo hizo alguna vez), pero tampoco puedo imaginar que a nadie le importe mucho.

Fortran tiene desde Fortran 90, pero requiere que use la recursivepalabra clave para decirle que una subrutina es recursiva.

PL / I era más o menos lo mismo: la recursión era compatible, pero había que decirle explícitamente qué procedimientos eran recursivos.

Sin embargo, dudo que haya muchos más que eso. Cuando llega el momento, la prohibición de la recursión fue principalmente algo que IBM hizo en sus diseños de lenguaje, por la sencilla razón de que los mainframes IBM (360/370/3090 / ...) no admiten una pila en el hardware. Cuando la mayoría de los idiomas provenían de IBM, en su mayoría prohibían la recursividad. Ahora que todos provienen de otros lugares, la recursión siempre está permitida (aunque debo agregar que algunas otras máquinas, especialmente la Cray 1 original, tampoco tenían soporte de hardware para una pila).

Jerry Coffin
fuente
Las computadoras de Control Data del período tampoco admitían la recursividad (las llamadas de subrutina se realizaron con una instrucción que modificó el código para insertar un salto a la instrucción de llamada + 1). Cuando Wirth desarrolló Pascal en el 6600, presumiblemente tuvo que encontrar una nueva forma de llamar a las subrutinas.
David Thornley
@David: sí, y no es casualidad, también fueron diseñados por Seymour Cray. Una vez tuve que mirar el compilador Pascal 6000, pero no recuerdo haber visto lo que hizo para generar (¿simular?) Marcos de pila.
Jerry Coffin
notably the original cray 1Entonces, ¿no necesitas recurrencia para clonar dinosaurios? Supongo que realmente depende de nosotros los monos balancearse entre los árboles.
normanthesquid
2
incluso CAML (y OCAML, F #) necesitan funciones recursivas explícitamente marcadas.
jk.
1
@Panzercrisis: No estoy seguro de si IBM estuvo involucrado en el x86, pero sus mainframes actuales se remontan directamente al IBM 360, que salió al mercado en 1964, por lo que el diseño básico es anterior al x86 en un par de décadas más o menos.
Jerry Coffin
16

Wikipedia dice:

Los primeros idiomas como Fortran no admitían inicialmente la recursividad porque las variables se asignaron estáticamente, así como la ubicación de la dirección de retorno.

http://en.wikipedia.org/wiki/Subroutine#Local_variables.2C_recursion_and_re-entrancy

FORTRAN 77 no permite la recursividad, Fortran 90 sí (las rutinas recursivas deben declararse explícitamente).

La mayoría de los compiladores de FORTRAN 77 permiten la recursividad, algunos (por ejemplo, DEC) requieren el uso de una opción de compilador (vea el capítulo de opciones de compilador). El GNU g77, que se ajusta estrictamente al estándar Fortran 77, no permite la recursividad en absoluto.

http://www.ibiblio.org/pub/languages/fortran/ch1-12.html

Robert Harvey
fuente
Iirc había al menos un compilador FORTRAN 77 que, si bien técnicamente soportaba la recursión, el número total de marcos de pila que podía tener eran tan pequeños que la recursión no era utilizable efectivamente para muchos problemas
jk.
6

El lenguaje de programación OpenCL no admite recursividad. (ver sección 6.8 de la especificación OpenCL )

La motivación actual para eso es a) la falta de espacio para las pilas profundas b) el deseo de conocer, estáticamente, las asignaciones totales requeridas para optimizar el rendimiento en presencia de grandes conjuntos de registros y una amplia alineación.

Esto puede aplicarse a otros lenguajes de programación de GPU, por ejemplo, lenguajes de sombreado.

grussel
fuente
2

Algunos compiladores de c para microcontroladores pequeños no admiten recursividad, presumiblemente porque tienen un tamaño de pila extremadamente limitado.

Jeanne Pindar
fuente
Algunos de esos microcontroladores (por ejemplo, la familia PIC16) solo tienen una pila de llamadas de hardware (no accesible por instrucciones) y no tienen ninguna otra forma de pila, por lo que las funciones no pueden tener variables locales cuando se utiliza la recursión (ya que claramente se necesita una pila de datos para eso ...) Referencia: en.wikipedia.org/wiki/PIC_microcontroller#Stacks
Ale
1

BASIC, en los días de números de línea, tendía a tener un pobre soporte de recursividad. Muchos (¿todos?) BÁSICOS de esa época admitían llamadas gosub anidadas, pero no admitían una manera fácil de pasar parámetros o devolver valores de una manera que fuera útil para la auto-llamada.

Muchas de las primeras computadoras tenían problemas con la recursividad, porque usaban instrucciones de llamada que escribían la dirección del remitente al comienzo de la rutina llamada (PDP8, la familia de máquinas IAS, probablemente más arquitecturas con las que no estoy familiarizado), generalmente de tal manera que era el código de máquina para "Saltar a la instrucción después de la que llamó a la rutina".

Vatine
fuente
1

Depende de lo que quieras decir con " soporte ". Para admitir la recursión, necesita una pila donde volver a instanciar las variables locales en cada reingreso.

Incluso si el lenguaje no tiene el concepto de variables locales, si tiene el concepto de "subrutina" y tiene una forma de gestionar una indexación entre variables idénticas (también conocido como matriz), puede aumentar / disminuir un índice global en cada entrada / salida de una función y acceder a través de ella a un miembro de una o más matrices.

No sé si esto se puede llamar "soporte". Los hechos son que escribí una función recursiva con ZX-Spectrum BASIC, como lo hice en Fortran77 como en COBOL ... siempre con ese truco.

Emilio Garavaglia
fuente
1

El lenguaje ensamblador no admite directamente la recursividad: debe "hacerlo usted mismo", generalmente introduciendo parámetros en la pila de máquinas.

mikera
fuente
2
Admite la recursividad en la medida en que admite llamadas a métodos. Por lo general, hay una CALLinstrucción, que empuja automáticamente la IP a la pila antes de saltar a la subrutina, y unas RETinstrucciones que introducen la dirección de retorno en la IP. No hay razón para que no puedas tener CALLtu propio punto de entrada.
Blorgbeard el
@Blorgbeard: absolutamente cierto, aunque diría que esto es insuficiente para contar como "admite la recursividad" en el sentido común, ya que no maneja los parámetros necesarios para la llamada recursiva.
mikera
1
Bueno, las llamadas recursivas técnicamente no necesitan parámetros, ¿verdad? void f() { f(); }es recursivo
Blorgbeard el
Técnicamente no. Pero poder codificar un caso trivial no significa en mi humilde opinión que deba describir el ensamblaje como "soporte de recursión". Los usos más prácticos de la recursividad requieren parámetros.
mikera 01 de
Supongo que podrías decir eso. Pero en ese caso, el ensamblaje tampoco admite bucles (debe CMP y JNZ manualmente). Supongo que es una cuestión de lo que llamas "apoyo".
Blorgbeard