Int - PowerPoint PPT Presentation

About This Presentation
Title:

Int

Description:

Title: Cb00853-1 Lenguajes de programaci n Author: Carlos Rodr guez Lucatero Last modified by: Campus Ciudad de M xico Created Date: 8/8/2001 2:20:44 AM – PowerPoint PPT presentation

Number of Views:71
Avg rating:3.0/5.0
Slides: 50
Provided by: Carlos375
Category:
Tags: environement | int

less

Transcript and Presenter's Notes

Title: Int


1
Intérpretes
  • Estudio de la semántica de programas a través de
    los interpretes
  • Proceedimientos que toman árboles abstractos de
    sintaxis de un programa y realizan el cálculo
    indicado.
  • Es un programa que consulta estructuras de datos
    y realiza acciones dependiendo de la estructura.
  • Parser, unparser,apply, reductores del cálculo
    lambda.
  • Los intérpretes que desarrollaremos revelaran la
    semántica de lenguajes de programación para
    entender los lenguajes que estudiaremos

2
Intérpretes
  • En el curso se desarrollará un intérprete simple.
  • Este reflejará la semántica fundamental de muchos
    lenguajes de programación moderna.
  • Lo construiremos en etapas comenzando por las
    formas más simples como son literales, variables
    y aplicaciones.Después agregaremos otras formas
    una por una.
  • Una parte importante de la especificación de
    cualquier lenguaje de programación es el conjunto
    de valores que el lenguaje manipularávalores
    expresados y valores denotados.

3
Intérpretes
  • Los valores expresados son los posibles valores
    de expresiones, y los valores denotados son los
    valores afectados a variables.
  • Por ejemplo, existen muchas clases de valores
    expresados tales como números, parejas,
    caracteres y cadenas, pero solo hay un tipo de
    valores denotados celdas que contienen valores
    expresados.
  • Por simplicidad, nuestro lenguaje tendrá solo dos
    tipos de valores expresados enteros y
    procedimientos.

4
Intérpretes
  • Por el momento, los valores denotados serán los
    mismos que los valores expresados. Escribiremos
    esto como sigue
  • Expressed ValueNumberProcedure
  • Denoted ValueNumberProcedure
  • Usamos ecuaciones como estas como recordatorio
    informal de valores expresados y denotados, para
    cada uno de nuestros intérpretes.
  • También hacemos distinción entre lenguaje
    definido y lenguaje de definición.
  • En nuestro caso el lenguaje de definición es
    Scheme.

5
Sintaxis abstracta
ltexpgtltinteger-literalgt
lit (datum) ltvarrefgt
ltoperatorgt ltoperandsgt app
(rator rands) ltoperatorgtltvarrefgt(ltexpgt) ltopera
ndsgt( )(ltoperandgt ,ltoperandgt) ltoperandgtlt
expgt ltvarrefgtltvargt
varref (var)
6
Expresiones típicas de nuestro lenguaje
3 n (3, n) add1((3, n)) (add1)((3, n)) Los
árboles de sintaxis abstracta son construidos,
como antes, con registros con definiciones de
tipos basados en los nombres abstractos dados
por la gramática. (define-record lit
(datum)) (define-record varref (var)) (define-reco
rd app (rator rands))
7
Registros variantes y variant-case
  • Un tipo que combina uno o mas tipos es llamado
    union type.
  • Un árbol es la unión de nodos interiores y hojas
  • Un union type cuyos alternativas son records se
    les llama registros variantes.
  • Scheme no provee directamente tipos variantes,
    pero pueden usarse implicitamente por medio del
    uso de predicados para cada tipo.
  • En el curso se usaran con cierta frecuencia los
    registros variantes, por lo cual conviene tener
    de ramificación sobre este tipo de registro.

8
Registros variantes y variant-case
  • Mas aún, cuando el tipo ha sido identificado, es
    útil afectar todos o algunos de los valores de
    sus campos con variables nombradas después de sus
    campos.
  • La forma especial que realiza ambos servicios es
    el variant-case cuya sintáxis es

(variant-case record-expression ( name1
field-list1 consequent1) ( namen
field-listn consequentn) (else alternative))
9
Intérprete simple usando variant-case
(define eval-exp (lambda (exp)
(variant-case exp (lit (datum) datum)
(varref (var) (apply-env init-env var))
(app (rator vrands) (let ((proc
(eval-exp rator)) (args
(eval-rands rands))) (apply-proc
proc args))) (else (error Invalid
abstract syntax exp))))) (define eval-rands
(lambda (rands) (map eval-exp rands)))
10
Comentarios sobre el intérprete
  • El campo rands del registro app contiene una
    lista de árboles sintácticos abstractos para
    aplicaciones de operandos.
  • El árbol sintáctico abstracto para add1((3, n))
    y (add1)((3, n)) sería

(app (varref add1) ( (app
(varref ) ( (lit 3) (varref n)))))
11
Comentarios sobre el intérprete
  • En el intérprete anterior, el procedimiento
    principal, eval-exp, le es pasado el árbol
    sintáctico abstracto de una expresión y regresa
    el valor de la expresión.
  • Sigue un patrón familiar, despachando en función
    del tipo de registro en la raíz del árbol.
  • El primer caso es fácil Si exp es una literal,
    regresa datum.
  • Si exp es un nodo que representa una variable, el
    valor de la expresión debe de ser el valor de
    afectación de la variable.Ahora hay que decidir
    de donde vamos a obtener dicho valor. Necesitamos
    dar un environement una función finita que toma
    el símbolo y regresa el valor asociado.

12
Comentarios sobre el intérprete
  • Este environement es consultado para hallar el
    valor de cualquier variable en el lenguaje.
  • En este lenguaje por el momento habrá un solo
    environement incial init-env
  • Definimos un ADT para environements tomando el
    ADT de función finita

(define the-empty-env (create-empty-ff)) (define
extend-env extend-ff) (define apply-env apply-ff)
13
Comentarios sobre el intérprete
  • Cuando se evalúa una variable, el intérprete solo
    necesita consultar su valor en init-env. Entonces
    tenemos la siguiente clausula del variant-case en
    eval-exp
  • Dado que el operador puede ser una expresión,
    debemos de evaluarla para obtener el
    procedimiento a llamar. Esto es llevado
    facilmente a cabo con la llamada recursiva
  • El lenguaje que estamos interpretando usa un
    orden de evaluación aplicativo los operandos son
    evaluados antes de llamar al procedimiento.
    (eval-rands)

(varref (var) (apply-env init-env var))
(eval-exp rator)
14
Comentarios sobre el intérprete
  • Como realizar las aplicaciones depende de la
    representación de los procedimientos.
  • Aislamos dicha dependencia dentro del
    procedimiento apply-proc.
  • Volviendo a la representación de procedimientos
    primitivos

ltproceduregtltprim-opgt
prim-proc(prim-op) ltprim-opgtltadditiongt

ltsubstractiongt -
ltmultiplicationgt
ltincrementgt
add1
ltdecrementgt sub1
15
Comentarios sobre el intérprete
  • Esta especificación dice que hay solo un tipo de
    procedimiento primitivo, y que hay cinco de
    estos.
  • Estos procedimientos son representados por
    records del la forma (define-record prim-proc
    (prim-op))
  • Esto nos permitirá hacer la distinción de otros
    tipos de procedimientos.
  • El único elemento almacenado en prim-proc el
    símbolo que nombra al operador.
  • Los procedimientos make-prim-proc y apply-proc
    definen un ADT para procedimientos
  • Todos lo que apply-proc hace hasta el momento es
    verificar que su primer argumento es un
    procedimiento primitivo y después invoca
    apply-prim-op

16
Procedimientos apply-proc y apply-prim-op
(define apply-proc (lambda (proc args)
(variant-case proc (prim-proc
(prim-op) (apply-prim-op args)) (else
(error Invalid procedure proc))))) (define
apply-prim-op (lambda (prim-op args)
(case prim-op (() ( (car args) (cadr
args))) ((- ) (- (car args) (cadr
args))) (( ) ( (car args) (cadr
args))) ((add1) ( (car args) 1))
((sub1) (- (car args) 1)) (else
(error Invalid prim-op name prim-op)))))
17
Comentarios
Podriamos haber representado los operadores
primitivos de manera que apply-prim-op realice su
trabajo. El este caso elegimos representar cada
operador por un símbolo el mismo símbolo que
medio ambiente inicial usará como nombre para ese
operador primitivo. Por lo tanto podemos
construir el medio ambiente inicial como
(define prom-op-names ( - add1 sub1)) (define
init-env (extend-env prim-op-names
(map make-prim-proc prim-op-names)
the-empty-env))
18
Comentarios
Esto completa nuestro primer intérprete. Antes de
poder probarlo, sin embargo, necesitamos una
parte que parsee expresiones e invoque eval-exp.
Hay varios enfoques para construir esta parte.Una
es ignorar los detalles de la sintaxis concreta y
escribir nuestras expresiones como estructuras de
lista. Entonces en vez de escribir add1( (3, n
)), escribiremos (add1 ( 3 n)). Para este
enfoque, todo lo que necesitamos es un
procedimiento parse, que tome una lista de
Scheme, un símbolo, o un número y regrese el
correspondiente árbol de sintáxis abstracta
gt(run (add1 2)) 3
gt(define run (lambda (x) (eval-exp
(parse x)))) gt(run 5) 5
19
Evaluación condicional
  • Para el estudio de la semántica de nuetro
    lenguaje agregaremos algunas características que
    aparecen en una amplia gama de lenguajes de
    programación.
  • Para cada característica, agregaremos una regla
    de producción a ltexpgt, una especificación formal,
    e incluiremos una línea de variant-case en
    eval-exp para manejar el nuevo nodo del árbol de
    sintáxis abstracta para el nuevo tipo.

ltexpgt if ltexpgt then ltexpgt else ltexpgt if
(test-exp then-exp else-exp)
(define-record if (test-exp then-exp
else-exp)) para evitar agregar booleanos
0false y true (define true-value? (lambda
(x) (not (zero? x))))
--gt if 1 then 2 else 3 2 --gtif -(3,(1,2)) then
2 else 3 3
20
Evaluación condicional
  • Este comportamiento se obtiene agregando la
    siguiente clausula a eval-exp

(if (test-exp then-exp else-exp) (if
(true-value? (eval-exp test-exp))
(eval-exp then-exp) (eval-exp else-exp)))
Este código utiliza la forma especial if de
Scheme para definir la forma if del lenguaje que
estamos definiendo, lo cual pone de manifiesto
nuestra dependencia en el entendimiento del
lenguaje de definición que en éste caso es Scheme.
21
Afectación local
  • Abordaremos el problema de la creación de
    variables locales en el contexto de la forma let.
  • Agregamos al lenguaje interpretado una sintaxis
    en la cual la palabra reservada let es seguida de
    una seria de declaraciones, la palabra reservada
    in, y el cuerpo. Por ejemplo

let x 5 y 6 in (x, y)
22
Afectación local
  • La forma entera let es una expresión, como lo es
    también su cuerpo, entonces las formas let pueden
    anidarse.
  • Las reglas de alcance léxico usual para
    estructuras de bloque se pueden aplicar la
    region de afectación de una declaración let es el
    cuerpo de la expresión let, y las afectaciones
    interiores crean hoyos en el alcance de las
    afectaciones mas externas.
  • Las referencias a x en la primera applicación se
    refiere a la declaración externa, mientras que
    las declaraciones en la segunda se refieren a la
    mas interna lo cual da 18.

let x 3 in let x (x, x) in (x, x)
23
Sintaxis concreta del let
ltexpgt let ltdeclsgt in ltexpgt
let (decls body) ltdeclsgtltdeclgtltdeclgt
ltdeclgtltvargtltexpgt
decl (var exp)
La sintaxis abstracta usa los siguientes tipos de
recgistro (define-record let (decls
body)) (define-record decl (var exp)) El campo
decls del let tendrá una lista no vacía de
registros decl. El body del let deberá evaluarse
en un environement en el cual las variables
declaradas esten afectadas por valores de las
expresiones en su lado derecho, mientras que las
otras afectaciones deberán tomarse del medio
ambiente en el cual la expresion completa de let
es evaluada.
24
Intérprete con let
(define eval-exp (lambda (exp env)
(variant-case exp (lit (datum)
datum) (varref (var) (apply-env env
var)) (app (rator rands)
(let ((proc (eval-exp rator env))
(args (eval-rands rands env)))
(apply-proc proc args)))
(if (test-exp then-exp else-exp)
(if (true-value? (eval-exp test-exp env))
(eval-exp then-exp env)
(eval-exp else-exp env))) (let
(decls body) (let ((vars (map
decl-gtvar decls)) (exps
(map decl-gtexp decls))) (let
((new-env (extend-env vars
(eval-rands exps env)
env)))
(eval-exp body new-env))))
(else (error Invalid abstract syntax
exp)))))
25
Procedimientos
  • Para que nuestro intérprete sea útil debemos
    permitir definir nuevos procedimientos diferentes
    a los que definimos en nuestro medio ambiente
    inicial.
  • Usaremos la sintaxis siguiente
  • Entonces podremos escribir como
  • Dado que proc puede usarse en cualquier parte
    donde se permita una expresión, también podemos
    escribir

ltexpgt proc ltvarlistgtltexpgt proc
(formals body) ltvarlistgt ( ) ( ltvarsgt
) ltvarsgt ltvargt ,ltvargt
let f proc (y, z) (y, -(z, 5)) in f(2, 8)
(proc (y, z) (y, -(z, 5)))(2, 8)
26
Procedimientos
  • Cuando se aplica un procedimiento, su cuerpo es
    evaluado en un medio ambiente que afecta los
    parámetros formales del procedimiento con los
    argumentos de la aplicación.
  • Lo anterior requiere que se retengan las
    afectaciones al momento que el procedimiento fué
    creado. Cosidere el ejemplo siguiente
  • Con el fin de retener dichas afectaciones, este
    debe ser un paquete cerrado, independiente del
    medio ambiente en el que es usado.

let x 5 in let f proc (y, z) (y, -(z, x))
x 28 in f(2, 8)
27
Procedimientos
  • Dicho paquete es llamado cerradura o closure.
  • A fin de que sea autocontenido, una cerradura
    debe de contener el cuerpo del procedimiento, la
    lista de sus parámetros formales, y las
    afectaciones a sus variables libres.
  • Es conveniente almacenar el medio ambiente de
    creación completo, en vez de solo guardar las
    afectaciones a las variables libres.
  • En una versión compilada, en la cual los cálculos
    de direcciones léxicas ya se realizaron, solo se
    requiere guardar en el closure el número de
    parámetros formales, junto con las afectaciones a
    variables libres y la referencia al código
    compilado del cuerpo.

(define-record closure (formals body env))
28
Procedimientos
  • Hay que modificar apply-proc para que reconozca
    closures.
  • Podemos describir los datos que apply-proc
    necesita reconocer con la ecuación siguiente
  • El procedimiento apply-proc primero checa que
    tipo de procedimiento fué pasado. Si fué un
    closure , simplemente invoca al cuerpo del
    closure en un medio ambiente extendido apropiado.

Procedure Primitive Procedure closure
29
Procedimientos
(define apply-proc (lambda (proc args)
(variant-case proc (prim-proc
(prim-op) (apply-prim-op prim-op args))
(closure (formals body env)
(eval-exp body (extend-env formals args env)))
(else (error Invalid procedure
proc)))))
Cuando una expresión proc es evaluada, todo lo
que se hace es construir un closure y regresarlo
inmediatamente.
30
Procedimientos
(define eval-exp (lambda (exp env)
(variant-case exp (proc (formals
body) (make-closure formals body
env)) )))
El cuerpo del procedimiento no se evalúa aqui no
puede ser evaluado hasta que los valores de los
parámetros formales se conocen, cuando el closure
es aplicado a algunos argumentos.
31
Intérprete con procedimientos
(define eval-exp (lambda (exp env)
(variant-case exp (lit (datum)
datum) (varref (var) (apply-env env
var)) (app (rator rands)
(let ((proc (eval-exp rator env))
(args (eval-rands rands env)))
(apply-proc proc args)))
(if (test-exp then-exp else-exp)
(if (true-value? (eval-exp test-exp env))
(eval-exp then-exp env)
(eval-exp else-exp env))) (let
(decls body) (let ((vars (map
decl-gtvar decls)) (exps
(map decl-gtexp decls))) (let
((new-env (extend-env vars
(eval-rands exps env)
env)))
(eval-exp body new-env))))
(proc (formals body)
(make-closure formals body env))
(else (error Invalid abstract syntax exp)))))
(define apply-proc (lambda (proc args)
(variant-case proc (prim-proc
(prim-op)(apply-prim-op
prim-op args)) (closure
(formals body env) (eval-exp body
(extend-env formals
body env))) (else
(error Invalid procedure
proc)))))
32
Asignaciones a variables
  • Queremos agregar a nuestro intérprete
    asignaciones ()
  • Primero hay que cambiar nuestra abstracción de
    medio ambiente, pues como está no permite
    modificar el valor de afectación de una variable.
    Es decir que los valores expresados y los
    denotados son los mismos.
  • En la modificación introduciremos indirección en
    las afectaciones, es decir que las variables
    estaran afectadas por localidades de memoria.
  • Scheme no permite modificar localidades de
    memoria, pero si permite cambios en elementos
    mutables de estructuras de datos por medio de por
    ej. set-cdr!. Usaremos celdas para modelar
    localidades de memoria y modificaremos el
    intérprete por medio de los siguientes dos
    cambios.

Denoted Value Cell (Expressed Value)
33
Asignaciones a variables
(extend-env formals (map make-cell args)
env)
(extend-env formals args env)
en lugar de
Segundo, cuando las variables son referenciadas,
es necesario desreferenciarlas ya que sus
afectaciones son ahora celdas. Entonces en el
variant-case del eval-exp hay que hacer el
siguiente cambio.
(varref (var) (cell-ref (apply-env
env var)))
en lugar de
(varref (var)(apply-env env var))
Este cambio al aplicarlo al paso de parámetros es
lo que se conoce como llamada por valor.
34
Asignaciones a variables
en la sintáxis abstracta
hay que agregar ltexpgtltvargtltexpgt
varassign (var exp)
Hay que definir el siguiente tipo de
records (define-record varassign (var exp)) En
eval-exp hay que agregar la cláusula
siguiente (varassign (var exp) (cell-set!
(apply-env env var) (eval-exp exp env)))
35
Intérprete con asignaciones y llamadas por valor
(define eval-exp (lambda (exp env)
(variant-case exp (lit (datum)
datum) (varref (var) (cell-ref
(apply-env env var))) (app (rator
rands) (let ((proc (eval-exp
rator env)) (args
(eval-rands rands env)))
(apply-proc proc args))) (if
(test-exp then-exp else-exp) (if
(true-value? (eval-exp test-exp env))
(eval-exp then-exp env)
(eval-exp else-exp env))) (let
(decls body) (let ((vars (map
decl-gtvar decls)) (exps
(map decl-gtexp decls))) (let
((new-env (extend-env vars
(eval-rands exps env)
env)))
(eval-exp body new-env))))
(proc (formals body) (make-closure
formals body env)) (varassign (var
exp) (cell-set! (apply-env env
var) (eval-exp exp env))) (else
(error Invalid abstract syntax exp)))))
(define apply-proc (lambda (proc args)
(variant-case proc (prim-proc
(prim-op)(apply-prim-op
prim-op args)) (closure
(formals body env) (eval-exp body
(extend-env
formals (map make-cell
args) env))) (else
(error Invalid procedure
proc)))))
36
Recursión
  • Tenemos 2 enfoques para implementar recursividad
  • El primer enfoque es el de los combinadores Y, el
    cual es muy importante desde el punto de vista
    teórico ya que solo requiere de tener la
    habilidad para crear y aplicar operadores de
    primara clase. Por ejemplo

Como convertirlo a una función recursiva? Hay
que definir una función Y tal que (Y f) sea
nuestro procedimiento recursivo. La suposición de
que la recursión puede ser obtenida por
referencia a g puede ser satisfecha si afectamos
g con (Y f) con la aplicación (f (Y f)) es decir
que (Y f) (f (Y f)).Entonces Y puede
ser definida como (lambda (f) ((lambda (x) (f
(x x))) (lambda (x) (f (x x)))))
Para definir en cálculo lambda un procedimiento
para el factorial (lambda (g) (lambda (n)
(if (zero? n) 1 ( n (g (- n 1)))))) Pongamos
que ésta es llamada f.
37
Recursión
  • Podríamos implementar directamente un combinador
    Y de orden aplicativo pero sería muy ineficiente.
  • El segundo enfoque es el usado para definir
    letrec en Scheme.

(letrec ((var1 exp1) (varn expn)) body) gt
(let ((var1 ) (varn )) (let ((v1
exp1) (vn expn)) (set! var1 v1)
(set! varn vn)
unspecified) body)
38
Recursión
  • De esta forma los procedimientos recursivos son
    creados encerrandolos en un medio ambiente que
    incluye las variables a las cuales afectarán.
  • Tratar de hacer referencia a alguna de las vari
    en alguna expj puede dar resultados extraños,
    pero después de ejecutar los set! todas las
    celdas contendran los valores correctos.
  • Si cada expi es una expresión lambda, entonces
    tenemos la garantía de que ninguna variable del
    letrec será referenciada prematuramente.
  • El orden de evaluación de las expi no es
    importante.
  • Este enfoque implementa la recursión
    introduciendo ciclos en la estructura de datos
    que reperesenta el medio ambiente de la ejecución.

39
Recursión
  • Por ejemplo, el medio ambiente creado por la
    rutina que se muestra a continuación contiene una
    circularidad. El medio ambiente contiene una
    afectación que apunta a un closure que a su vez
    contiene una referencia al medio ambiente.

(letrec ((fact (lambda (n)
(if (zero? n) 1
( n (fact (- n 1))))))) )
...
fact
(n)
closure
40
Recursión
  • En la mayoría de los lenguajes solo los
    procedimientos se pueden definir recursivamente,
    y se crean ambientes circulares por el mismo
    mecanismo que crea los procedimientos recursivos.
  • Veremos como agregar recursión a nuestro
    intérprete sin circularidad.
  • Usaremos una variación en la sintáxis del letrec
    que restringe el lado derecho de la declaración
    recursiva a expresiones proc. La sintáxis
    abstracta es

ltexpgt letrecproc ltprocdeclsgt in ltexpgt
letrecproc(procdels

body) ltprocdelsgtltprocdelgtltprocdelgt ltprocdel
gtltvargtltvarlistgtltexpgt procdel (var
formals body)
41
Recursión
  • La mano izquierda de la declaración recursiva es
    el nombre del procedimiento recursivo y la lista
    de parámetros.
  • A la derecha del sigo es el cuerpo del
    procedimiento.
  • Ejemplos

letproc fact(x) if zero(x) then 1 else (x,
fact(sub1(x))) in fact(6) o letproc even(x)
if zero(x) then 1 else odd(sub1(x)) odd(x)
if zero(x) then 0 else even(sub1(x)) in odd(13)
42
ADT de medio ambiente sin closures circulares
(define-record extended-rec-env (vars vals
old-env)) (define extend-rec-env (lambda
(procdels env) (make-extend-rec-env
(map procdecl-gtvar procdels)
(list-gtvector (map (lambda
(procdecl)
(make-proc
(procdecl-gtformals procdecl)
(procdecl-gtbody procdecl)))
procdecls)) env))) (define
apply-env (lambda (env var)
(variant-case env (extended-rec-env
(vars vals old-env) (let ((p
(ribassoc var vars cals fail)))
(if (eq? p fail)
(apply-env old-env var)
(make-closure (proc-gtfornals p) (proc-gtbody
p) env)))) )))
43
Alcance y asignación dinámicos
  • Existen 2 enfoques para reorganizar la
    información en un medio ambiente.
  • Primer enfoque es, alcance dinámico, el cual es
    un mecanismo de afectación que agrega
    expresividad adicional al precio de hacer los
    programas bastante dificiles de entender.
  • Segundo enfoque es,asignación dinámica, que da
    mas expresividad al alcance dinámico,sin
    abandonar la claridad del alcance léxico.

44
Alcance dinámico
  • Ya dijimos que cuando un procedimiento es
    aplicado, es el medio ambiente en el cual éste
    fué creado el que se usa para evaluar el cuerpo.
  • Esto se necesita para que las variables tengan un
    alcance léxico, pero además se requiere de que se
    forme un nuevo closure cada que se avalúa una
    expresión proc.
  • Parecería mas simple evaluar el cuerpo en el
    ambiente de aplicación. Considere el programa
    siguiente
  • Por el alcance léxico el p tomaría el valor de
    a3 y la expresión entera dería por resultado 25.
    Si por el contrario p se evaluara en su ambiente
    de aplicación daría 35.En éste último caso el
    alcance es dinámico y no léxico.

let a 3 in let p proc (x) (x, a)
a 5 in (a, p(2))
45
Alcance dinámico
  • Lo anterior se conoce como afectación dinámica y
    obedece la siguiente reglaUna afectación
    dinámica es existente durante la evaluación del
    cuerpo asociado con la forma de la afectación.
    Referencias a una variable afectada dinámicamente
    se refiere a la más reciente afectación existente
    de dicha variable.
  • Es mas dificil razonar sobre el alcance dinámico
    que sobre el léxico pero es mas facil de
    implementar. Dado que los procedimientos no son
    cerrados sobre su ambiente de creación, la única
    información que debemos guardar en un
    procedimiemnto es la lista de parámetros formales
    y su cuerpo. La clausula correspondiente en el
    variant-case de eval-exp es (proc (formals body)
    exp).
  • La evaluación de expresiones proc se hace mas
    simple y eficiente.
  • Cuando apply-proc recibe un record tipo proc ,
    debe de extender el ambiente corriente para
    obtener el ambiente en el cual evaluar el cuerpo.
    Esto obliga a pasarlo como parámetro a
    apply-proc.
  • El ambiente obedece una política LIFO

46
Intérprete con alcance dinámico
(define eval-exp (lambda (exp env)
(variant-case exp (lit (datum)
datum) (varref (var) (cell-ref
(apply-env env var))) (app (rator
rands) (let ((proc (eval-exp
rator env)) (args
(eval-rands rands env)))
(apply-proc proc args env))) (if
(test-exp then-exp else-exp) (if
(true-value? (eval-exp test-exp env))
(eval-exp then-exp env)
(eval-exp else-exp env))) (let
(decls body) (let ((vars (map
decl-gtvar decls)) (exps
(map decl-gtexp decls))) (let
((new-env (extend-env vars
(eval-rands exps env)
env)))
(eval-exp body new-env))))
(proc (formals body) exp))
(varassign (var exp) (cell-set!
(apply-env env var) (eval-exp exp env)))
(else (error Invalid abstract syntax
exp)))))
(define apply-proc (lambda (proc args
current-env) (variant-case proc
(prim-proc (prim-op)(apply-prim-op
prim-op args))
(proc (formals body) (eval-exp body
(extend-env
formals (map make-cell
args) current-env)))
(else (error Invalid procedure
proc)))))
47
Asignación dinámica
  • Los intérpretes que se han examinado
    introdujeron afectación con alcance léxico. Estas
    afectaciones tienen una extensión indefinida, es
    decir que son retenidas tanto tiempo como se
    necesiten.
  • Las afectaciones son retenidas en el closure
    tanto tiempo como se necesite tener acceso a
    éste.
  • Después vimos como crear afectaciones con alcance
    dinámico y vimos como tienen existencia dinámica.
  • Ahora exploramos otra alternativa asignaciones
    con extensión dinámica en afectaciones con
    alcance léxico.
  • Esto es llamado afectación fluída o fluid binding.

48
Asignación dinámica
  • En el lenguaje definido asignación dinámica
    usando la forma de sintáxis concreta y abstracta
    siguiente
  • El efecto de
  • es asignar temporalmente el valor de exp a var,
    evaluar body, reasignar a var su valor original,
    y regresar el valor de body. Por ejemplo en

ltexpgtltvargtltexpgt during ltexpgt dynassign
(var exp body)
var exp during body
let x 4 in let p proc (y) (x, y) in (x
7 during p(1), p(2))
49
Asignación dinámica
  • El valor de x, que es libre en p , es 7 en la
    llamada p(1), pero es regresada a 4 en la llamada
    p(2), entonces el valor de la expresión es 86
    14.
  • Esto puede implementarse en una clausula del
    variant-case como sigue

(dynassign (var exp body) (let ((a-cell
(apply-env env var)) (b-cell
(make-cell (eval-exp exp env))))
(cell-swap! a-cell b-cell) (let ((value
(eval-exp body env))) (cell-swap! a-cell
b-cell) value)))
Write a Comment
User Comments (0)
About PowerShow.com