1 la máquina g. 2 introducción g: una implementación de lenguajes funcionales basada en...

30
1 La máquina G

Upload: marcela-serna

Post on 12-Mar-2015

5 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

1

La máquina G

Page 2: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

2

Introducción

G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987).

Instanciación como es implementada por la función instantiate es bastante lenta: debe recursivamente recorrer el cuerpo del SC (template) cada vez que una instanciación es efectuada.

La gran idea de G:

Antes de ejecutar un programa, traducir el cuerpo de cada supercombinador a una secuencia de instrucciones que al ser ejecutadas construyan una instancia del mismo.

Page 3: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

3

Introducción (2)La ejecución del código generado es necesariamente más rápida

que invocar una función de instanciación, ya que todas las instrucciones están dedicadas a construir una instancia. No existen instrucciones dedicadas a recorrer el template, esto es resuelto cuando se efectúa la traducción.

La ejecución de un programa se divide en dos partes:

i) un compilador produce un código intermedio del programa (tiempo de compilación)

ii) en la segunda etapa el código intermedio es ejecutado

(tiempo de ejecución)

El SC original puede ser descartado una vez compilado.

Page 4: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

4

Introducción (3)

Usamos un compilador a código-G para para transformar un programa fuente en una secuencia de instrucciones de lenguaje de máquina (abstracta).

Una buena máquina abstracta cumple las siguientes propiedades:

i) debe poder ser fácilmente traducida a código de cualquier máquina concreta

ii) el código de la máquina debe ser fácilmente generado a partir del lenguaje fuente

Una máquina abstracta es una brecha muy importante entre el lenguaje fuente y el código de una máquina concreta particular.

Page 5: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

5

Ejemplo

Analizaremos un ejemplo muy simple para ilustrar a G.

Consideremos la función

f g x = K g x

La secuencia de instrucciones de código-G a la que será compilada es la siguiente:

Push 1

Push 1

Mkap

Pushglobal K

Mkap

Slide 3

Unwind

Page 6: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

6

Ejemplo (2)

@ @ xf g

Estado de la máquina antes de ejecutar la secuencia de instrucciones para f. La espina fue desplegada y punteros a @denotan los argumentos a ser ligados por g y x

@ @ xf g

Push 1

La instrucción Push usa direccionamiento relativo al topedel stack, no f, 0, 1, ...

@ @ xf g

Push 1

Notar que después de este Push tnemos un puntero a gen el tope del stack. Aunque el offset sea el mismo (1) esto funciona porque le Push anterior incremento el tope.

Page 7: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

7

Ejemplo (3)

@ @ xf g

@

Este diagrama muestra que pasa luego de efectuar la ins-trucción Mkap. Toma dos punteros del stack y construyeun nodo de plicación a partir de ellos, dejando un punteroal resultado en el tope del stack.

Mkap

@ @ xf g

@K

Pushglobal K

El efecto de ejecutar Pushglobal K es el de pushear un puntero al SC K en el tope del stack.

Page 8: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

8

Ejemplo (4)

@ @ xf g

@

K @

Mkap

Esta última aplicación de Mkap completa la instancia-ción del cuerpo de f.Ahora podemos reemplazar la expresión original, f g x,con el cuerpo recientemente instanciado.

@K @ g x

En la primer versión de G que veremos, que no es lazy,simplemente se desliza el cuerpo tres lugares en el stack,descartando los tres punteros que habia. Esta acción es la efectuada por la instrucción Slide 3.

Slide 3

La instrucción final Unwind fuerza a la máquina a seguir evaluando.

Page 9: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

9

OptimizacionesCompilación posibilita otro tipo de optimizaciones, además de la

ya remarcada de no tener que atravesar templates.

Considere la siguiente definición

f x = x + x

Las máquinas de reducción de grafos descriptas anteriormente intentarán evaluar x dos veces. La segunda, sin embargo, se encontrarán con que x ya fue evaluado.

Una implementación compilada pude darse cuenta que x ya estará evaluada y directamente omitirá el paso de evaluación.

Page 10: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

10

Secuencia de código para crear templates

Recordemos la definición de la función instantiate:instantiate body var value =

case body of

Var x -> if x == var then value else body

App f e -> App (instantiate f var value) (instantiate e var value)

Lam bvs e -> if var bvs

then body

else Lam bvs (instantiate e var value)

Definición recursiva!

En vez, trataremos de compilar una secuencia lineal de instrucciones que permita efectuar la instanciación de una expresión.

Page 11: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

11

Sistemas de transición de estados

Describiremos la implementación de reducción de grafos usansdo un sistema de transición de estados (STE).

Un STE es un formalismo que permite describir el comportamiento de una máquina secuencial. En cualquier momento la máquina está en algún estado, habiendo comenzado en un cierto estado inicial.

Si el estado de la máquina machea (es una premisa válida de ) una de las reglas de transición de estado, entonces esta regla es aplicada (un paso de inferencia es efectuado) especificando así un nuevo estado para la máquina.

Cuando no hay matching le ejecución para (no es posible seguir construyendo una derivación).

Nuestra máquina además será determinística.

Page 12: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

12

Evaluación postfija de expresiones aritméticas

El objetivo de construír una secuencia lineal de instrucciones para instanciar expresiones se asemeja al proceso de evaluar expresiones aritméticas en forma postfija. Exploraremos esta analogía antes de proseguir con la máquina G.

El lenguaje de expresiones aritméticas consiste de números, suma y multiplicación:

data AExpr = Num Int | Plus AExpr AExpr | Mult AExpr AExpr

Se supone que este lenguaje tiene un significado asociado, el que se puede describir con la siguiente función

Page 13: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

13

Evaluación postfija de expresiones aritméticas (2)

aInterpret :: Aexpr -> Int

aInterpret (Num n) = n

aInterpret (Plus e1 e2) = aInterpret e1 + aInterpret e2

aInterpret (Mult e1 e2) = aInterpret e1 * aInterpret e2

Alternativamente se podría compilar la expresión a una secuencia fija de operadores (o instrucciones). Por ejemplo, la expresión

2 + 3 * 4 se representaría con la secuencia:

[INum 2, INum 3, INum 4, IMult, IPlus]

Definimos las instrucciones para nuestra máquina postfija con el siguiente tipo:

data AInstruction = INum Int | IPlus | IMult

Page 14: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

14

Evaluación postfija de expresiones aritméticas (3)

El estado del evaluador es un par, formado por una secuencia de operadores y un stack de números. El significado de una secuencia de código es definido por las siguientes reglas de transición.

[] [n]=> n

INum n : i ns=> i n : ns

IPlus : i n0:n1: ns=> i (n0 + n1) : ns

IMult : i n0:n1: ns=> i (n0 * n1) : ns

Page 15: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

15

Evaluación postfija de expresiones aritméticas (4)

Para generar la secuencia de código postfijo para una expresión debemos definir un compilador.

Este toma una expresión y retorna una secuencia de instrucciones, las que al ser ejecutadas computarán el valor de la expresión.

aCompile :: AExpr -> [Ainstruction]

aCompile (Num n) = [INum n]

aCompile (Plus e1 e2) = aCompile e1 ++ aCompile e2 ++ [IPlus]

aCompile (Mult e1 e2) = aCompile e1 ++ aCompile e2 ++ [IMult]

Page 16: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

16

Usando código postfijo para construír grafos

Para crear una instancia del cuerpo de un SC podemos usar la misma técnica. En este caso los valores en el stack serán direcciones de partes de las expresión que está siendo instanciada.

Habrá una diferencia, sin embargo, ya que las instrucciones tendrán generalmente el efecto lateral de alojar nodos en un heap, Mkap es un buen ejemplo.

Un punto importante a recordar al hacer uso del stack: El mapeo de valores del stack que correponden a nombres de variables cambiará a medida que agreguemos o saquemos objetos del stack. Esto tendrá que ser tenido en cuenta cuando compilemos una expresión.

Page 17: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

17

Qué ocurre luego de haber efectuado una instanciación?

Una vez que hemos generado una instancia del cuerpo de un SC, debemos arreglar el stack y continuar con el proceso de evaluación. Al completar la evaluación de un secuencia postfija de un SC de n argumentos el stack se encontrará en el siguiente estado:

i) en el tope estará la dirección en el heap del cuerpo recien instanciado, e digamos

ii) luego habrá n+1 punteros. Usándolos podremos acceder a los argumentos usados en el proceso de instanciación.

iii) el último de estos punteros apunta a la raíz de la expresión recien instanciada.

Page 18: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

18

Qué ocurre luego de haber efectuado una instanciación? (2)

@ @ en

en-1

@f e1

e

Debemos reemplazar el redex con la nueva instancia y luego sacar n items del stack usando la instrucción Slide. Para encontrar el próximo SC debemos comenzar a desplegar la espina nuevamente, usando la instrucción Unwind.

El código para la función f x1 ... xn = e es:

<código para construír una instancia de e>Slide n+1Unwind

Page 19: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

19

Una máquina G minimal

Presentaremos a partir de ahora el código para una máquina G y su compilador.

Comenzaremos con una versión muy simple de la máquina (no perezosa), donde no se efectúan actualizaciones de raíces de redexes y tampoco se efectúa el tratamiento de expresiones aritméticas.

Gradualmente iremos construyendo versiones más sofisticadas donde se incorporarán todos los elemntos de pereza y cálculo que conforman la máquina G completa.

Page 20: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

20

Estado

El estado de la máquina minimal se representará por la siguiente cuádrupla:

(Code, Stack, Heap, Globals)

Code: es una lista de instrucciones. Notación: (i : is)

Stack: es un stack de direcciones, cada una identifica un nodo en el Heap. Estos nodos forman la espina de la expresi’on que est’a siendo evaluada. Notación: (a1 : s)

Heap: es una colección de nodos etiquetados. Notación: h[a:nodo]

Globals: dirección de cada SC ( y luego de primitivas)

Page 21: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

21

Instrucciones

El stream de instrucciones es un objeto de tipo GmCode y es simplemente una lista de instrucciones

type GmCode = [Instruction]

Inicialmente tendremos sólo 6 instrucciones:

data Instruction = Unwind

| Pushglobal Name

| Pushint Int

| Push Int

| Mkap

| Slide Int

Page 22: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

22

Stack y Heap

El stack de la máquina es una lista de direcciones de nodos en el Heap

data GmStack = [Addr]

Usaremos una estructura abstracta para definir el Heap de la máquina

data GmHeap = Heap Node

En la máquina G minimal habrá sólo tres tipos de nodos: números, aplicaciones y globales.

data Node = NNum Int

| NAp Addr Addr

| NGlobal Int GmCode

Page 23: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

23

Globales

Como luego transformaremos la máquina para que evalúe perezosamente es importante que en principio haya sólo un nodo para cada función global.

La dirección de una global puede ser determinada haciendo un lookup de su valor (definición) en una lista de asociación

type GmGlobals = Assoc Name Addr

Page 24: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

24

El evaluadorEl evaluador de G, eval, está definido de forma de producir una

lista de estados. El primero de ellos es aquél construído por el compilador. Si existe un estado final entonces el resultado de la evaluación se encontrará en el tope del stack de este último estado.

eval :: GmState -> [GmState]

eval state = state : restStates

where

restStates | gmFinal state = []

| otherwise = eval nextState

nextStates = step state

gmFinal s = case (getCode s) of [] -> True ; _ -> False

El intérprete de G termina cuando la secuencia de código a ejecutar es vacía.

Page 25: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

25

Ejecutando un paso

La función step se define de forma tal que efectúa una transición de estado basada en la instrucción que está ejecutando:

step :: GmState -> GmState

step state = dispatch i (putCode is state)

where (i:is) = getCode state

La función despacha la instrucción corriente i y reemplaza la secuencia de código corriente con la secuencia is. Esto corresponde a avanzar el program counter en una máquina real.

La función dispatch simplemente selecciona una transición de estado a ejecutar. Ahora presentaremos las reglas de transición, una por cada objeto en Instruction.

Page 26: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

26

Pushglobal

Comenzamos con la instrucción Pushglobal, que usa el componente GmGlobals del estado para encontrar el único nodo Nglobal en el heap que contiene la función global f. Si no lo encuentra un mensaje de error tendría que ser desplegado:

Pushglobal f : i s h m[f:a] => i a:s h m

La siguientes transiciones implementan la construcción del cuerpode un SC.

Page 27: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

27

Pushint y Mkap

La transición para Pushint aloja un nodo entero en el heap:

Pushint n : i s h m => i a : s h[a:Nnum n] m

La instrucción Mkap usa las dos direcciones que están en el tope delstack para construír un nodo aplicación en el heap:

Mkap : i a1 : a2 : s h m => i a : s h[a:Nap a1 a2] m

Page 28: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

28

Push

La instrucción Push efectúa una copia de un argumento que ha sido pasado a una función. Para esto, debe mirar a través del nodo de aplicación que es apuntado desde el stack. También se debe saltear el nodo que apunta al SC que está en el stack.

Push n : i a0 : ... : an+1 : s h[an+1:NAp an a’n] m => i a’n : a0 : ... : an+1 : s h m

El rearreglo del stack, que ocurre luego que un SC ha sido instanciadoes efectuado por la instrucción Slide

Slide n : i a0 : ... : an : s h m => i a0 : s h m

Page 29: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

29

Unwind

Unwind es la instrucción más compleja porque reemplaza el loop externo de la función de instanciación. Esta es siempre la última instrucción de una secuencia. El nuevo estado a construír depende del item que se encuentre en el tope del stack, que a su vez determina la regla de transición a aplicar.

Primero consideramos el caso en el que el tope es un número. En este caso la evaluación debe terminar:

[Unwind] a : s h[a:Nnum n] m => [] a : s h m

Page 30: 1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación

30

Unwind (2)

Si lo que hay es un nodo de aplicación en el tope entonces debemos continuar unwinding desde el próximo nodo:

[Unwind] a : s h[a:Nap a1 a2] m => [] a1 : a : s h m

La regla más complicada ocurre cuando hay un nodo global en el topePuede suceder que esté aplicada a suficientes argumentos o no. En el primer caso hay un error de tipos. En el segundo saltaremos al códigodel SC. En la regla esto se expresa moviendo el código al componentede código de la máquina

[Unwind] a0 : ... : an : s h[a0:Nglobal n c] m => c a0 : ... : an : s h m