• No se han encontrado resultados

Jerarquías de intérpretes

lenguajes que no son Turing completos pueden ser considerados lenguajes de pro- gramación genuinos, por ejemplo: el lenguaje de demostradores de teoremas como Coq e Isabelle, que sólo permiten funciones que terminan; algunos lenguajes deriva- dos de la teoría de tipos; o el lenguaje propuesto en [144] que consta de funciones primitivas recursivas de alto orden. Incluso un lenguaje mucho más simple, como el de una calculadora electrónica, es un lenguaje de programación interesante, aunque poco potente.

Para definir una jerarquía basada en los lenguajes de programación, introducimos la noción defunción de compilacióncomo una función que traduce un programa𝑝en otro𝑝′equivalente, posiblemente escrito en un lenguaje de programación diferente.

Definición 5(Función de compilación y simulación de lenguajes). Dadas dos fun- ciones de interpretación𝑖 ∈ 𝑃 → 𝐵e𝑖′ ∈ 𝑃′ → 𝐵′, decimos que𝑐 ∈ 𝑃′ → 𝑃es una función de compilaciónentre𝑃′y𝑃si para cada𝑝∈ 𝑃

𝑖.(𝑐.𝑝′) = 𝑖′.𝑝′

En este caso decimos que𝐼simulaa𝐼′, denotado por𝐼

𝑐 𝐼. En caso que también valga

𝐼 ⊑𝑐′ 𝐼′(para𝑐′∈ 𝑃 → 𝑃′) decimos que los intérpretes sonlenguaje-equivalentes.

Como una consecuencia directa de esta definición, el orden⊑implica lógicamen- te el orden⊆previamente definido. Lo recíproco también es cierto.

Lema 1. Dados dos intérpretes𝐼e𝐼′:

1. Si𝐼′⊆ 𝐼, entonces existe𝑐 ∈ 𝑃′→ 𝑃tal que𝐼′⊑𝑐 𝐼. 2. Si𝐼 ⊑𝑐 𝐼′(para alguna𝑐 ∈ 𝑃 → 𝑃′), entonces𝐼 ⊆ 𝐼′.

Ejemplo 4. Sea𝑃un lenguaje de programación que consiste de dos instrucciones:𝑠𝑢𝑚.𝑥

y𝑚𝑢𝑙𝑡.𝑥que producen respectivamente la suma y multiplicación de𝑥con el valor alma- cenado en un acumulador, y almacenan el resultado en el mismo. Sea𝐼 un intérprete para este lenguaje que acepta secuencias de tales instrucciones como programas. Así𝐼se comporta como un evaluador de expresiones algebráicas conformadas por+y×.

Sea𝑃′otro lenguaje de programación que consiste de tres operaciones:𝑠𝑢𝑚.𝑥definida como la anterior,𝐴que accede al valor almacenado en el acumulador, y𝑟𝑒𝑝𝑒𝑎𝑡.𝑥.𝑆que repite la secuencia de instrucciones𝑆una cantidad𝑥de veces. Sea𝐼′un intérprete para

𝑃′.

Es fácil de demostrar que existe una función de compilación que traduce cada ins- trucción𝑚𝑢𝑙𝑡.𝑥en un programa𝑟𝑒𝑝𝑒𝑎𝑡.(𝑥 − 1).(𝑠𝑢𝑚.𝐴). Por lo tanto𝐼′simulaa𝐼. Lo opuesto no es verdadero, ya que𝐼′se comporta como un evaluador de expresiones alge- bráicas conformadas por+,×e hiper-exponenciación.

24 2. Intérpretes

Mas allá del hecho que los órdenes previamente definidos son equivalentes, el segundo tiene su propia importancia ya que los lenguajes de programación y la tra- ducción entre ellos juegan un rol fundamental en las prácticas de las ciencias de la computación. Ya que son dispositivos diseñados, los intérpretes se construyen usual- mente de acuerdo a un lenguaje de programación predefinido en lugar del conjunto de comportamientos subyacentes, que permanece implícito. Más aún, suele suceder que el conjunto de comportamientos no es (o no puede ser) descripto de forma pre- cisa. Como un caso particular, el conjunto de lasfunciones efectivamente computables no puede ser definido excepto por la relación entre diferentes formalismos, conocida como la tesis de Church-Turing.

Lema 2(Tesis de Church-Turing). Las funciones recursivas, las máquinas de Turing, y un lenguaje imperativo estándar, etc. vistos como los respectivos intérpretes𝑅, 𝑇, 𝐼de las “funciones efectivamente computables”, sonlenguaje-equivalentes, y para cualquier otro intérprete𝐼′tal que𝑅 ⊑ 𝐼′necesariamente vale que𝐼′⊑ 𝑅.

Consideremos dos intérpretes 𝐼 e𝐼′, que implementan las funciones𝑖 ∈ 𝑃 →

(𝐷 → 𝐵)e 𝑖′ ∈ 𝑃′ → (𝐷′ → 𝐵′)respectivamente. La jerarquía definida por los órdenes⊑y⊆especifica que un intérprete, por caso𝐼, puede simular a otro,𝐼′, y consecuentemente comportarse como tal, pero no estipula cómo se lleva adelante esa simulación. No es un requerimiento que la función de compilación se pueda ejecu- tar mecánicamente, ni que sea una función computable. En la literatura se propone el concepto decompiladorcomo un procedimiento mecánico para traducir efectiva- mente un programa escrito en un lenguaje de programación en otro. Si requerimos que la traducción sea ejecutada por𝐼, esto es, existe un compilador𝑐𝑜𝑚𝑝 ∈ 𝑃, la condición de la definición 5 se transforma en

𝑖.(𝑖.𝑐𝑜𝑚𝑝.𝑝′) = 𝑖.𝑝

Aquí𝑖.𝑐𝑜𝑚𝑝.𝑝′es la “ejecución” del compilador con el dato de entrada𝑝′que resulta en otro programa, que es la entrada de𝑖. Notar que debe suceder que𝑃 ⊆ 𝐷.

Dado el rol central que tiene la noción de compilador en la teoría de la compu- tación, se puede argumentar que puede reemplazar a la noción de intérprete para determinar cuándo un formalismo sintáctico es un lenguaje de programación, y con- secuentemente, cuándo un sistema es computacional. Sin embargo el concepto de in- térprete es más primitivo, porque para que un compilador (o más general, cualquier programa) sea “ejecutado”, siempre es necesario un intérprete (como se observa a partir de la ecuación anterior). Mientras que el concepto de compilador tiene cierta capacidad explicativa, que permite comprender un lenguaje de programación en tér- minos de otro lenguajemas primitivo, es un intérprete quien finalmente caracteriza los comportamientos que tal lenguaje es capaz de codificar. La ecuación anterior nos

2.2. Jerarquías de intérpretes 25

permite decir informalmente, que “la composición de un intérprete con (la ejecución de) un compilador resulta en un intérprete”.

Requerir que una función de compilación pueda ser codificada como un progra- ma para un intérprete dado impone condiciones más fuertes no sólo en los compor- tamientos que tal intérprete produce, sino tambien en suprogramabilidad. Siguiendo esta dirección, es posible definir un orden lógicamente más fuerte que⊆(y que⊑).

Definición 6(Interpretación). Dadas dos funciones de intepretación𝑖 ∈ 𝑃 → 𝐵e

𝑖′∈ 𝑃→ 𝐵, y respectivos intérpretes𝐼e𝐼, e𝑖𝑛𝑡 ∈ 𝑃un programa particular que toma elementos de𝑃′como entrada, decimos que𝑖𝑛𝑡es unprograma-intérpretepara𝑃′si

𝑖.𝑖𝑛𝑡 = 𝑖′

En este caso decimos que𝐼 interpretaa𝐼′, denotado como𝐼′ ⪯ 𝐼. Si además vale que

𝐼 ⪯ 𝐼′decimos que𝐼e𝐼soninter-interpretables. Cuando𝐼 ⪯ 𝐼 decimos que𝐼esauto- interpretable, que es una propiedad bien conocida de los sistemas Turing completos.

La diferencia entre las jerarquías de simulación e interpretación es sutil. Nueva- mente consideremos dos intérpretes𝐼e𝐼′, que implementan las funciones𝑖 ∈ 𝑃 → (𝐷 → 𝐵)e𝑖′∈ 𝑃′→ (𝐷′→ 𝐵′)respectivamente. Mientras que el orden𝐼′⊑ 𝐼deter- mina una relación deser parteentre los comportamientos subyacentes (i.e.𝐵′⊆ 𝐵), el orden𝐼′⪯ 𝐼caracteriza una relación deser un elemento(𝑖′∈ 𝐷 → 𝐵). Como con- secuencia, no sólo𝐼puede finalmente comportarse como𝐼′, sino que el lenguaje de programación de𝐼es capaz de codificar en un único programa el conjunto completo de comportamientos del intérprete𝐼′.

Para clarificar la distinción, supongamos que𝐼′⊑ 𝐼 y𝐼⪯ 𝐼. Así, combinando las condiciones de las definiciones 5 y 6 obtenemos

𝑖.(𝑐.𝑝′) = 𝑖.𝑖𝑛𝑡.𝑝

En el lado izquierdo,𝑐.𝑝′es un programa diferente para cada𝑝. En el lado derecho, el programa es siempre el mismo,𝑖𝑛𝑡, mientras que𝑝′es sólo el dato de entrada de

𝑖𝑛𝑡.

La ecuación anterior permite entrever la relación lógica entre⊑y⪯. Si𝐼′ ⪯ 𝐼 vale, es fácil de imaginar cómo definir una función de compilación de𝑃′a𝑃: asignar a cada𝑝′∈ 𝑃un programa como𝑖𝑛𝑡pero con𝑝ocupando el lugar del parámetro de entrada.

Lema 3. Sean𝑖 ∈ 𝑃 → 𝐵e𝑖′ ∈ 𝑃′ → 𝐵′ dos funciones de intepretación,𝐼 e𝐼′los intérpretes que implementan𝑖e𝑖′respectivamente. Si𝐼⪯ 𝐼, entonces𝐼⊆ 𝐼.

Interpretación e implementación

Reconsideremos la definición de la relación de interpretación (def. 6). El nom- bre elegido para referirnos al programa característico𝑖𝑛𝑡puede resultar confuso en

26 2. Intérpretes

principio, pero no es arbitrario. Previamente introducimos el concepto de intérprete como una generalización del concepto, comúnmente comprendido como un progra- ma que “ejecuta” otros programas. Elprograma-intérprete𝑖𝑛𝑡es tal programa.

Además, losprogramas-intérpretesjuegan un papel fundamental en la relación de implementación. Unprograma-intérprete es un intérprete de acuerdo a la relación de implementación que presentamos, en el siguiente sentido. Consideremos dos fun- ciones de interpretación𝑖 ∈ 𝑃 → 𝐵e𝑖′ ∈ 𝑃′ → 𝐵′, e𝐼 un sistema computacional respecto a𝑖. Consideremos además que existe unprograma-intérprete𝑖𝑛𝑡 ∈ 𝑃, tal que

𝑖.𝑖𝑛𝑡 = 𝑖′

Es fácil de ver que el intérprete𝐼instanciado con𝑖𝑛𝑡(i.e.fijando𝑖𝑛𝑡como la entrada de𝐼) satisface el criterio para ser considerado unaimplementaciónde la función de in- terpretación𝑖′, y por lo tantoes un intérprete. Esto nos permite decir informalmente que “la composición de un intérprete con unprograma-intérpretees un intérprete”. Además, para cualquier otro sistema𝐼′que implementa𝑖, se satisface que𝐼⪯ 𝐼.

Cabe remarcar que no es elmerosistema (físico)𝐼quien implementa a𝑖′, sino que la función de interpretación𝑖interviene en la relación. Así es que𝐼, considerado co- mo sistema computacional respecto a𝑖y provisto con𝑖𝑛𝑡, es también computacional respecto a𝑖′. Esto muestra que la relación de implementación es lo suficientemente general como para considerar no sólo sistemas “concretos”.

Ejemplo 5. Según el ejemplo 1 (pág. 21), el “computer” es una implementación del for- malismo de las máquinas de Turing (𝑇). Ahora, la Máquina de Turing Universal (𝑢𝑡𝑚), “ejecutada” por elcomputor, es un intérprete que toma una codificación de la tabla de transición de una máquina arbitraria junto con su entrada, y se comporta como ella. En otras palabras

𝑇.𝑢𝑡𝑚 = 𝑇

Como consecuencia, el formalismo de las máquinas de Turing es auto-interpretable, y el programa particular𝑢𝑡𝑚codifica el poder computacional completo del formalismo.

Ejemplo 6. El ejemplo más común de un intérprete es unprograma-intérpreteejecu- tándose en una computadora digital, que “ejecuta” unscriptescrito en un lenguaje de programación corriente. Elscript, sus datos y el valor resultante son codificados en algu- na estructura de datos delprograma-intérprete. El conjunto de comportamientos queda definido por la semántica del lenguaje.

Por ejemplo, los programasperlypythonsonprogramas-intérpretesde los lengua- jes homónimos, yghcipara el caso de Haskell.

Los programas-intérpretes se utilizan extensivamente en la teoría de la compu- tación y en la ingeniería desoftware para dar cuenta de la complejidad de los sis- temas informáticos. Y las funciones de interpretación juegan un papel importante,