Pulse aquí para obtener el archivo

Anuncio
Home Page
Title Page
Contents
JJ
II
J
I
Semántica de los Conceptos
Fundamentales de los Lenguajes de
Programación
Profesor: Juan Francisco Diaz
[email protected]
Page 1 of 42
Asistente de Docencia: Gerardo M. Sarria M.
[email protected]
Go Back
Full Screen
Close
Quit
May 17, 2002
Home Page
Title Page
Ligadura Local
Contents
JJ
II
La forma let es una expresión que sirve para crear una variable
ligada. Su sintaxis concreta es:
hexpresióni ::= let {hidentificadori = hexpresióni}∗ in hexpresióni
let-exp (ids rands body)
J
I
Con la que se pueden crear expresiones como:
Page 2 of 42
let x = 1
in let x = +(x,2)
in add1(x)
Go Back
Full Screen
Close
Quit
En este ejemplo la referencia de x en la primera aplicación se refiere a la
declaración de más afuera, mientras que la referencia a la x en la segunda
aplicación se refiere a la declaración de más adentro, y por lo tanto el valor
de toda la expresión es 4.
Home Page
Title Page
La sintaxis abstracta de una expresión es ahora:
Contents
JJ
II
J
I
Page 3 of 42
Go Back
Full Screen
Close
Quit
Ligadura Local (cont.)
(define-datatype expression expression?
(lit-exp
(datum number?))
(var-exp
(id symbol?))
(primapp-exp
(prim primitive?)
(rands (list-of expression?)))
(if-exp (test-exp true-exp false-exp)
(if (true-value? (eval-expression test-exp env))
(eval-expression true-exp env)
(eval-expression false-exp env)))
(let-exp
(ids (list-of symbol?))
(rands (list-of expression?))
(body expression?)))
Home Page
Title Page
Contents
JJ
II
J
I
Ligadura Local (cont.)
Una expresión let es evaluada de la siguiente forma:
1. Se evalúa la subexpresión correspondiente a las declaraciones, en el
ambiente original.
Page 4 of 42
2. Se extiende el ambiente con las variables de la declaración y sus
valores.
Go Back
Full Screen
Close
Quit
3. Se evalúa el cuerpo de la expresión let en el ambiente extendido.
Home Page
Title Page
El comportamiento de las ligaduras locales en el interpretador se
obtiene agregando la cláusula let-exp a eval-expression:
Contents
JJ
II
J
I
Page 5 of 42
Go Back
Full Screen
Close
Quit
Ligadura Local (cont.)
(define eval-expression
(lambda (exp env)
(cases expression exp
(lit-exp (datum) datum)
(var-exp (id) (apply-env env id))
(primapp-exp (prim rands)
(let ((args (eval-rands rands env)))
(apply-primitive prim args)))
(if-exp (test-exp true-exp false-exp)
(if (true-value? (eval-expression test-exp env))
(eval-expression true-exp env)
(eval-expression false-exp env)))
(let-exp (ids rands body)
(let ((args (eval-rands rands env)))
(eval-expression body (extend-env ids args env)))))))
Home Page
Title Page
Procedimientos
Para que el interpretador tenga más poder de expresión, se necesitan crear procedimientos. La siguiente sintaxis se usa para crear
procedimientos y aplicaciones:
Contents
JJ
II
J
I
Page 6 of 42
Go Back
Full Screen
hexpresióni ::= proc ({hidentificadori}∗(,) ) hexpresióni
proc-exp (ids body)
::=
(hexpresióni {hexpresióni}∗ )
app-exp (rator rands)
De esta manera se pueden crear programas como
let f = proc (y, z) +(y, -(z, 5))
in (f 2 28)
Los valores expresados y denotados, cambian con la inclusión de
procedimientos:
Valor Expresado = Valor Denotado = Número + ProcVal
Close
Quit
donde ProcVal es el conjunto de valores que representan los procedimientos.
Home Page
Title Page
Cuando un procedimiento es aplicado, su cuerpo es evaluado en el
ambiente en que fué creado, extendido con la ligadura de los parámetros
formales del procedimiento a los argumentos de la aplicación.
Contents
JJ
Procedimientos (cont.)
II
J
I
Por tanto, las variables que ocurren libres en el procedimiento se
evalúan en el ambiente que envuelve al procedimiento.
Ejemplo 1:
Page 7 of 42
Go Back
Full Screen
Close
Quit
let x = 5
in let f = proc (y, z) +(y, -(z, x))
x = 28
in (f 2 x)
Cuando se llama a f, su cuerpo debe ser evaluado en un ambiente que liga
y a 2, z a 28 y x a 5.
x es ligado a 5 ya que el alcance de la declaración interna no incluye la
declaración del procedimiento.
Home Page
Title Page
Contents
JJ
II
J
I
Page 8 of 42
Go Back
Procedimientos (cont.)
Para que un procedimiento retenga la ligadura que sus variables libres tienen en el momento que es creado, éste debe ser empaquetado, para
que pueda ser usado independiente del ambiente donde es llamado. Éste
paquete es llamado clausura (closure), y corresponderá al nuevo conjunto
de valores ProcVal.
ProcVal se puede pensar como un tipo de dato. La interfaz se puede
definir como un árbol de sintaxis abstracta representado por
(define-datatype procval procval?
(closure
(ids (list-of symbol?))
(body expression?)
(env environment?)))
En esta representación, apply-procval usa cases para tomar la clausura
e invocar el cuerpo de la clausura en el ambiente extendido:
Full Screen
Close
Quit
(define apply-procval
(lambda (proc args)
(cases procval proc
(closure (ids body env)
(eval-expression body (extend-env ids args env))))))
Home Page
Title Page
Procedimientos (cont.)
Contents
JJ
II
J
I
Page 9 of 42
Go Back
Ahora, se modificará eval-expression para que maneje procedimientos.
El código del cliente sólo puede manipular los procedimientos mediante la
interfaz de ProcVal, de modo que sea independiente de la representación
de los procedimientos.
Cuando un procedimiento es evaluado, se construye una clausura y
se retorna inmediatamente.
(define eval-expression
(lambda (exp env)
(cases expression exp
(proc-exp (ids body) (closure ids body env))
...)))
Full Screen
El cuerpo del procedimiento no es evaluado aquı́: no puede ser evaluado
hasta que los valores de los parámetros formales sean conocidos.
Close
Quit
Home Page
Title Page
Cuando una aplicación es evaluada, el operador y los operandos son
evaluados y el resultado es enviado a apply-procval.
Contents
JJ
II
J
I
Page 10 of 42
Go Back
Full Screen
Close
Quit
Procedimientos (cont.)
(define eval-expression
(lambda (exp env)
(cases expression exp
(app-exp (rator rands)
(let ((proc (eval-expression rator env))
(args (eval-rands rands env)))
(if (procval? proc)
(apply-procval proc args)
(eopl:error ’eval-expression
"Attempt to apply non-procedure ∼s" proc))))
...)))
Los operandos son denominados parámetros actuales. Ellos son expresiones y no deben ser confundidos con sus valores (llamados argumentos
del procedimiento) o con las variables ligadas o parámetros formales del
procedimiento.
Home Page
Title Page
Contents
Procedimientos (cont.)
JJ
II
J
I
Page 11 of 42
Go Back
Full Screen
Close
Quit
Ejercicio:
Calcule el resultado de la siguiente expresión (se escribe << exp >> para
denotar el árbol de sintaxis abstracta asociado con la expresión exp, y se
escribe [x = a, y = b]env en lugar de (extend-env ’(x y) ’(a b) env)).
(eval-expression <<let x = 5
in let x = 38
f = proc (y, z) *(y, +(x, z))
g = proc (u) +(u, x)
in (f (g 3) 17)>>
env0)
Home Page
Title Page
Recursión
Contents
JJ
II
J
I
Page 12 of 42
Para agregar la recursión en el interpretador, se tomará la forma de
las expresiones let cambiando su espacio de declaración y limitándolo a
expresiones tipo proc de esta manera::
hexpresióni ::= letrec
{hidentificadori ({hidentificadori}∗(,) ) = hexpresióni}∗
in hexpresióni
letrec-exp (proc-names idss bodies letrec-body)
Ejemplo 2:
Go Back
Full Screen
Close
Quit
letrec
fact(x) = if zero?(x) then 1 else +(x, (fact sub1(x)))
in (fact 6)
Home Page
Title Page
Contents
Recursión (cont.)
JJ
II
J
I
Page 13 of 42
Go Back
Full Screen
Close
Quit
Para evaluar una expresión letrec, se evalúa el cuerpo de la expresión en un ambiente extendido con las declaraciones dentro de la
misma expresión recursiva:
(define eval-expression
(lambda (exp env)
(cases expression exp
(letrec-exp (proc-names idss bodies letrec-body)
(eval-expression letrec-body
(extend-env-recursively proc-names idss bodies env)))
...)))
Home Page
Title Page
Recursión (cont.)
Contents
JJ
II
J
I
Page 14 of 42
Go Back
Full Screen
Close
Quit
El Tipo Abstracto de Dato environment es modificado para admitir una nueva variante:
(define-datatype environment environment?
(empty-env-record)
(extended-env-record
(syms (list-of symbol?))
(vals (list-of scheme-value?)
(env environment?))
(recursively-extended-env-record
(proc-names (list-of symbol?))
(idss (list-of (list-of symbol?)))
(bodies (list-of expression?))
(env environment?)))
Home Page
Title Page
Recursión (cont.)
Contents
JJ
II
J
I
El comportamiento de (apply-env e0 name) para la nueva variante
del tipo environment es el siguiente:
Sea e0 (extend-env-recursively proc-names idss bodies e), entonces
1. Si name es uno de los nombres en proc-names, e ids y body son la
lista de parámetros formales y el cuerpo del procedimiento (respectivamente), entonces (apply-env e0 name) = (closure ids body e0 ).
Page 15 of 42
2. Si no, entonces (apply-env e0 name) = (apply-env e name).
Go Back
Full Screen
Close
Quit
(define extend-env-recursively
(lambda (proc-names idss bodies old-env)
(recursively-extended-env-record
proc-names idss bodies old-env)))
Home Page
Title Page
Contents
JJ
II
J
I
Page 16 of 42
Go Back
Full Screen
Close
Quit
Recursión (cont.)
(define apply-env
(lambda (env sym)
(cases environment env
(empty-env-record ()
(eopl:error ’empty-env "No binding for ∼s" sym))
(extended-env-record (syms vals old-env)
(let ((pos (list-find-position sym syms)))
(if (number? pos)
(list-ref vals pos)
(apply-env old-env sym))))
(recursively-extended-env-record (proc-names idss
bodies old-env)
(let ((pos (list-find-position sym proc-names)))
(if (number? pos)
(closure
(list-ref idss pos)
(list-ref bodies pos)
env)
(apply-env old-env sym)))))))
Home Page
Title Page
Asignación de Variables
Contents
JJ
II
J
I
Page 17 of 42
Una expresión set asigna un valor a una variable. La forma begin
permite la evaluación de expresiones en orden retornando el último valor.
La sintaxis concreta de las asignaciones y la secuenciación es:
hexpresióni ::= set hidentificadori = hexpresióni
varassign-exp (ids rhs-exp)
::= begin hexpresióni {; hexpresióni}∗ end
begin-exp (exp exps)
La asignación agrega la siguiente variante al tipo de dato expresión:
Go Back
Full Screen
Close
Quit
(varassign-exp
(id symbol?)
(rhs-exp expression?))
Home Page
Asignación de Variables (cont.)
Title Page
Contents
JJ
II
J
I
Page 18 of 42
Go Back
Full Screen
Close
Quit
Al entrar la asignación, surge la pregunta:
entre asignación y ligadura?
¿Cuál es la diferencia
Una ligadura, crea una nueva asociación de un nombre con un valor,
mientras que la asignación cambia el valor de una ligadura existente.
Ligadura comprende la asociación de nombres con valores; asignación
comprende el compartimiento de valores entre diferentes procedimientos.
Ejemplo 3:
Considere el siguiente programa:
let x = 0
in letrec
even() = if zero?(x)
then 1
else begin set x = sub1(x); (odd) end
odd() = if zero?(x)
then 0
else begin set x = sub1(x); (even) end
in begin set x = 13; (odd) end
Los procedimientos even y odd comparten la variable x y se comunican
cambiando el estado de la variable, en vez de pasarse datos explicitamente.
Home Page
Title Page
Asignación de Variables (cont.)
Contents
JJ
II
J
I
Un ambiente es simplemente un tipo de dato que asigna valores a
variables.
Cuando se incluyeron los procedimientos, se encontró el problema de que
el estado del ambiente no era guardado en el momento de la aplicación de
procedimientos y esto ocasionaba el retorno de un valor errado.
Ejemplo 4:
Page 19 of 42
Go Back
Full Screen
Close
Quit
let z = 0
in let f = proc (y) *(y,z)
in let z = 1
in (f 2)
Este ejemplo en un principio evalúa a 2. Sin embargo, con la entrada de la
clausura, el ambiente, en el momento de la aplicación del procedimiento,
es guardado y la expresión retorna el valor correcto: 0.
Home Page
Title Page
Asignación de Variables (cont.)
Contents
Ahora, con la entrada de la asignación, surge otro problema.
JJ
II
J
I
Page 20 of 42
Go Back
Full Screen
Close
Quit
Ejemplo 5:
let z = 0
f = proc (x) z
in begin set z = 1;
(f 2)
end
La expresión anterior tiene el valor 0, en vez del valor 1.
Lo anterior debido a que en el momento de la asignación de z a 1, el
valor de dicha variable en el ambiente no cambió; lo que cambió fué el
valor de la asociación creada en la ligadura local. Luego en el llamado
al procedimiento se guarda el ambiente (donde z tiene el valor de 0) y se
retorna 0.
Home Page
Title Page
Asignación de Variables (cont.)
Contents
JJ
II
J
I
Page 21 of 42
Go Back
Para evitar el problema anterior, cada identificador debe denotar la
dirección de una ubicación en memoria (la memoria es también llamada
store). Dicha dirección se denomina referencia y lo que hace la asignación
es modificar su contenido.
Los valores denotados son ahora referencias cuyos valores son valores
expresados:
Valor Denotado =
Valor Expresado =
Ref(Valor Expresado)
Número + ProcVal
Las referencias o ubicaciones son tambien llamadas L-valores (valores que
se asocian con variables que aparecen al lado izquierdo (Left en inglés) de
la declaración de asignación).
Full Screen
De forma análoga, los valores expresados (que aparecen en el lado
derecho (Right) de la declaración de asignación) son llamados R-valores.
Close
Quit
Home Page
Title Page
Asignación de Variables (cont.)
Contents
JJ
II
J
I
Page 22 of 42
Go Back
Full Screen
Close
Quit
En el lenguaje que se está realizando, se creará un nueva referencia
para cada parámetro formal en cada llamado a procedimiento. Esta
polı́tica es conocida como llamado por valor. Cuando se asigna a un
parámetro formal, la asignación es local al procedimiento.
Ejemplo 4:
let x = 100
in let p = proc (x) let d = set x = add1(x)
in x
in +((p x), (p x))
El programa anterior retorna 202, ya que una nueva referencia es creada
para cada x en cada uno de los llamados a procedimiento.
Además, en cada llamado a procedimiento la asignación afecta sólo las
ligaduras internas.
Home Page
Asignación de Variables (cont.)
Title Page
Antes de implementar la asignación, se recuerda el concepto de ambiente.
Contents
Un ambiente puede verse como la estructura de la siguiente figura:
JJ
columna
II
lista de simbolos
´
J
I
Page 23 of 42
vector de valores
a
b
c
11 22 33
x
c
66 77
Go Back
Full Screen
Close
resto del ambiente
Quit
Home Page
Asignación de Variables (cont.)
Title Page
El tipo de dato ambiente es entonces:
Contents
JJ
II
J
I
(define-datatype environment environment?
(empty-env-record)
(extended-env-record
(syms (list-of symbol?))
(vals (list-of scheme-value?))
(env environment?)))
(define scheme-value? (lambda (v) #t))
Page 24 of 42
Los procedimientos son los siguientes:
Go Back
(define empty-env
(lambda ()
’()))
Full Screen
Close
Quit
(define extend-env
(lambda (syms vals env)
(cons (cons syms (list-vector vals)) env)))
Home Page
Title Page
Asignación de Variables (cont.)
Contents
Por último, el procedimiento para aplicar un ambiente:
JJ
II
J
I
Page 25 of 42
Go Back
Full Screen
Close
Quit
(define apply-env
(lambda (env sym)
(if (null? env)
(eopl:error ’apply-env "No binding for ~s" sym)
(let ((syms (car (car env)))
(vals (cdr (car env)))
(env (cdr env)))
(let ((pos (rib-find-position sym syms)))
(if (number? pos)
(vector-ref vals pos)
(apply-env env sym)))))))
Home Page
Asignación de Variables (cont.)
Title Page
Para implementar la asignación de variables, se incluirá el tipo de
dato reference, cuyas operaciones serán deref y setref!, que accesan
y almacenan el valor de la ubicación.
Contents
JJ
II
J
I
El tipo de dato contiene un vector (las referencias serán elementos
de un vector) y la posición del L-valor dentro de este vector:
(define-datatype reference reference?
(a-ref
(position integer?)
(vec vector?)))
Page 26 of 42
Go Back
Full Screen
La siguiente figura muestra una referencia a una ubicación en un vector que
contiene el 7. Se puede describir dicha referencia gráficamente dibujando
un apuntador al centro de la estructura, como se muestra en el lado derecho
del diagrama.
a−ref
2
Close
7
Quit
0
1
2
7
3
0
1
2
3
Home Page
Asignación de Variables (cont.)
Title Page
Las operaciones del tipo de dato se definen de la siguiente manera:
Contents
JJ
II
J
I
Page 27 of 42
Go Back
(define primitive-deref
(lambda (ref)
(cases reference ref
(a-ref (pos vec) (vector-ref vec pos)))))
(define primitive-setref!
(lambda (ref val)
(cases reference ref
(a-ref (pos vec) (vector-set! vec pos val)))))
(define deref
(lambda (ref)
(primitive-deref ref)))
Full Screen
Close
Quit
(define setref!
(lambda (ref val)
(primitive-setref! ref val)))
Home Page
Asignación de Variables (cont.)
Title Page
Contents
JJ
II
J
I
Ahora, se debe revisar el concepto de ambiente para hacer uso de
las referencias.
Se incluirá la operación apply-env-ref a la interfaz de ambiente para
que cuando se encuentre un identificador, se retorne la referencia en vez
de su valor.
El procedimiento apply-env se reescribirá en términos de apply-env-ref
y deref:
(define apply-env
(lambda (env sym)
(deref (apply-env-ref env sym))))
Page 28 of 42
Go Back
Full Screen
Close
Quit
(define apply-env-ref
(lambda (env sym)
(cases environment env
(empty-env-record ()
(eopl:error ’apply-env-ref "No binding for ~s" sym))
(extended-env-record (syms vals env)
(let ((pos (rib-find-position sym syms)))
(if (number? pos)
(a-ref pos vals)
(apply-env-ref env sym)))))))
Home Page
Title Page
Contents
Asignación de Variables (cont.)
JJ
II
Por último, para implementar la asignación de variables, simplemente se
agrega la siguiente cláusula a eval-expression:
J
I
(varassign-exp (id rhs-exp)
(begin
(setref!
(apply-env-ref env id)
(eval-expression rhs-exp env))
1))
Page 29 of 42
Go Back
Full Screen
Close
Quit
Explı́citamente se retorna 1, ya que lo que retorna setref! no está especificado, y siempre se tiene que retornar un valor expresado.
Home Page
Title Page
Paso de Parámetros
Contents
JJ
II
J
I
Page 30 of 42
Go Back
Full Screen
Close
Quit
La forma más común para el paso de parámetros es el llamado por
valor (visto anteriormente). Sin embargo, hay otras alternativas para el
mecanismo de paso de parámetros.
Ejemplo 5:
Considere la siguiente expresion:
let a = 3
p = proc (x) set x = 4
in begin (p a); a end
Bajo la semántica de llamado por valor, el valor denotado asociado con x
es una referencia que inicialmente contiene el mismo valor que la referencia asociada con a. Sin embargo, la asignación a x no tiene efecto en el
contenido de la referencia de a, por lo que el valor de toda la expresión es
3.
Home Page
Title Page
Contents
Paso de Parámetros (cont.)
JJ
II
J
I
Page 31 of 42
Algunas veces es deseable que se permita pasar a un procedimiento
variables con el objetivo de que éstas sean asignadas por dicho
procedimiento (es decir, que el valor de las variables cambien tanto
en el interior del procedimiento como en el llamado al procedimiento).
Lo anterior se realiza pasando al procedimiento una referencia a la
ubicación de la variable y no su contenido. Este mecanismo es denominado llamado por referencia.
Go Back
Full Screen
Close
Quit
Usando el llamado por referencia en el ejemplo 5, la signación de x
a 4 tendrı́a el efecto de asignar 4 a a, por lo que toda la expresión
retornarı́a 4 y no 3.
Home Page
Paso de Parámetros (cont.)
Title Page
Ejemplo 6:
Se tiene el programa para cambiar el valor de dos variables (swap):
Contents
JJ
II
J
I
Page 32 of 42
Go Back
Full Screen
Close
Quit
let a = 3
b = 4
swap = proc (x, y)
let temp = x
in begin
set x = y
set y = temp
end
in begin
(swap a b)
-(a,b)
end
Bajo el llamado por referencia, esto cambia los de valores de a y b retornando 1.
Si este programa fuera ejecutado con un interpretador con llamado por
valor, retornarı́a -1, ya que la asignación dentro del procedimiento no
tendrı́a efecto sobre las variables a y b.
Home Page
Title Page
Contents
JJ
II
J
I
Paso de Parámetros (cont.)
En los llamados por referencia, los identificadores aún denotan referencias
a valores expresados, luego los conjuntos no cambian:
Valor Denotado =
Valor Expresado =
Ref(Valor Expresado)
Número + ProcVal
Page 33 of 42
Go Back
Full Screen
Close
Quit
El único cambio ocurre cuando se crean nuevas referencias. En los llamados por valor, una nueva referencia es creada para cada evaluación de un
operando; en los llamados por referencia, una nueva referencia es creada
para cada evaluación de un operando distinto a una variable.
Home Page
Title Page
Contents
JJ
II
J
I
Page 34 of 42
Paso de Parámetros (cont.)
Para la implementación del llamado por referencia, una referencia
será (como en llamado por valor) una referencia a una ubicación en un
vector, pero dicho vector contendrá o los valores expresados o referencias
a valores expresados (llamados blanco directo y blanco indirecto respectivamente).
Un blanco directo corresponde al comportamiento del llamado por
valor, en el cual la nueva ubicación es creada; un blanco indirecto
corresponde al nuevo comportamiento del llamado por referencia, en el
cual no son creadas nuevas ubicaciones.
Un blanco es entonces un tipo de dato definido por
Go Back
Full Screen
Close
Quit
(define-datatype target target?
(direct-target
(expval expval?))
(indirect-target
(ref ref-to-direct-target?)))
Home Page
Title Page
Paso de Parámetros (cont.)
Contents
Los procedimientos que correspondientes a las variantes del tipo de
dato target son:
JJ
II
J
I
Page 35 of 42
Go Back
Full Screen
Close
Quit
(define expval?
(lambda (x)
(or (number? x) (procval? x))))
(define ref-to-direct-target?
(lambda (x)
(and
(reference? x)
(cases reference x
(a-ref (pos vec)
(cases target (vector-ref vec pos)
(direct-target (v) #t)
(indirect-target (v) #f)))))))
Home Page
Paso de Parámetros (cont.)
Title Page
Las nuevas definiciones de deref y setref! observan el tipo de
blanco para determinar el valor expresado a retornar o la ubicación a
cambiar
Contents
JJ
II
J
I
Page 36 of 42
Go Back
Full Screen
Close
Quit
(define deref
(lambda (ref)
(cases target (primitive-deref ref)
(direct-target (expval) expval)
(indirect-target (ref1)
(cases target (primitive-deref ref1)
(direct-target (expval) expval)
(indirect-target (p)
(eopl:error ’deref
"Illegal reference: ~s" ref1)))))))
(define setref!
(lambda (ref expval)
(let ((ref (cases target (primitive-deref ref)
(direct-target (expval1) ref)
(indirect-target (ref1) ref1))))
(primitive-setref! ref (direct-target expval)))))
Home Page
Title Page
Contents
JJ
II
J
I
Page 37 of 42
Go Back
Full Screen
Close
Quit
Paso de Parámetros (cont.)
El procedimiento eval-expression antes de la entrada del llamado
por referencia era:
(define eval-expression
(lambda (exp env)
(cases expression exp
(lit-exp (datum) datum)
(var-exp (id) (apply-env env id))
(varassign-exp (id rhs-exp)
(begin
(setref!
(apply-env-ref env id)
(eval-expression rhs-exp env))
1))
(primapp-exp (prim rands)
(let ((args (eval-rands rands env)))
(apply-primitive prim args)))
(if-exp (test-exp true-exp false-exp)
(if (true-value? (eval-expression test-exp env))
(eval-expression true-exp env)
(eval-expression false-exp env)))
...
)))
Home Page
Paso de Parámetros (cont.)
Title Page
Contents
JJ
II
J
I
Page 38 of 42
Go Back
Full Screen
Close
Quit
(define eval-expression
(lambda (exp env)
(cases expression exp
...
(proc-exp (ids body) (closure ids body env))
(let-exp (ids rands body)
(let ((args (eval-rands rands env)))
(eval-expression body (extend-env ids args env))))
(app-exp (rator rands)
(let ((proc (eval-expression rator env))
(args (eval-rands rands env)))
(if (procval? proc)
(apply-procval proc args)
(eopl:error ’eval-expression
"Attempt to apply non-procedure ~s" proc))))
(letrec-exp (proc-names idss bodies letrec-body)
(eval-expression letrec-body
(extend-env-recursively
proc-names idss bodies env))))))
Home Page
Title Page
Paso de Parámetros (cont.)
Contents
JJ
II
J
I
Page 39 of 42
Go Back
Full Screen
Close
Quit
Obeservando el código anterior, para implementar el llamado por
referencia se necesitan hacer varios cambios.
Para aplicaciones primitivas, simplemente se necesita evaluar las subexpresiones y pasar los valores a apply-primitive, de manera que en
eval-expression se escribe
(primapp-exp (prim rands)
(let ((args (eval-primapp-exp-rands rands env)))
(apply-primitive prim args)))
donde eval-primapp-exp-rands está definida por
(define eval-primapp-exp-rands
(lambda (rands env)
(map (lambda (x) (eval-expression x env)) rands)))
Home Page
Title Page
Paso de Parámetros (cont.)
Contents
Para ligadura local (formas let), se mantiene el comportamiento de
los llamados por valor, luego en eval-expression se escribe
JJ
II
J
I
(let-exp (ids rands body)
(let ((args (eval-let-exp-rands rands env)))
(eval-expression body (extend-env ids args env))))
donde eval-let-exp-rands y eval-let-exp-rand están definidas por
Page 40 of 42
Go Back
Full Screen
Close
Quit
(define eval-let-exp-rands
(lambda (rands env)
(map (lambda (x) (eval-let-exp-rand x env)) rands)))
(define eval-let-exp-rand
(lambda (rand env)
(direct-target (eval-expression rand env))))
Home Page
Title Page
Contents
JJ
II
J
I
Paso de Parámetros (cont.)
Para aplicación de procedimientos, se evalúa cada operando usando
eval-rand.
Si el operando no es una variable, entonces se crea una nueva ubicación retornando el blanco directo. Si el operando es una variable, ésta
denota una ubicación que contiene un valor expresado, luego se retorna
un blanco indirecto que apunta a dicha ubicación.
Si una variable está ligada a una ubicación que contiene un blanco
directo (el cual debe contener un valor expresado), entonces una referencia
a la ubicación es retornada como un blanco indirecto. Pero si la variable
está ligada a otra referencia, entonces dicha referencia es retornada.
Page 41 of 42
Go Back
Full Screen
Close
Quit
(define eval-rand
(lambda (rand env)
(cases expression rand
(var-exp (id)
(indirect-target
(let ((ref (apply-env-ref env id)))
(cases target (primitive-deref ref)
(direct-target (expval) ref)
(indirect-target (ref1) ref1)))))
(else
(direct-target (eval-expression rand env))))))
Home Page
Paso de Parámetros (cont.)
Title Page
Contents
JJ
II
J
I
Page 42 of 42
Ejemplo 7:
(proc (t, u, v, w)
(proc (a, b)
(proc (x, y, z)
set y = 13
a b 6)
3 v)
5 6 7 8)
Este ejemplo puede verse gráficamente como la operación de eval-rand
de la siguiente figura.
x
y
z
6
Go Back
a
Full Screen
b
3
Close
Quit
5
6
7
8
t
u
v
w
Descargar