Title: Paso de par
1Paso de parámetros y arreglos
2Gracias a los interpretes hemos explorado varias
características que ofrecen los lenguajes de
programación dentro de las cuales encontramos
- Las aplicaciones (llamadas a procedimiento)
- Resolución de nombres (gracias al establecimiento
de un ambiente) - Condicionamiento de la ejecución.
- Creación de variables locales.
- Creación de procedimientos por parte del usuario,
- Asignación de variables
- Recursión
- Alcance dinámico y asignación o afectacion
dinámica
3Otras características de los LP
- Modificando nuestro interprete podremos
- Seguir explorando las características de los LPs
- Expresar alternativas semánticas para los LP de
una manera clara y precisa de forma a enfantizar
sus diferencias esenciales.
4Otras características de los LP
- Extensiones a nuetro interprete para estas
sesiones - Manejo de arreglos.
- Paso de parámetros.
- Llamadas por Valor.
- Llamadas por referencia.
- Llamadas por el valor del resultado.
- Llamadas por resultado.
- Llamadas por nombre (o por retraso).
- Llamadas por necesidad.
- Parámetros opcionales
- Parámetros por nombre (vs. posición)
5Añadiendo arreglos
- Muchos lenguajes de programación incluyen
estructuras de datos compuestos de multiples
elementos conocidos como agregados. - En Scheme encontramos los siguientes agregados
- Pares.
- Vectores.
- Cadenas de caracteres.
- Existen dos representaciones para los agregados
- Directa (ej. arreglos en pascal). El paso de un
parámetro de este tipo a un procedimiento se hace
por valor i.e. se hace una copia del agregado. - Indirecta (ej. C). El paso de un parámetro de
este tipo a un procedimiento se hace por
referencia i.e. se envía un apuntador al agregado
que se quiere enviar como parámetro.
6Añadiendo arreglos
Agreguemos a nuestro interprete las siguientes
extensiones para el manejo de arreglos
- Una nueva forma que permita la creación de
arreglos y su asociación a una varable. - Una expresión que permita la asociación local de
una variable con un arreglo. - Una expresión que permita acceder a un elemento
de un arreglo. - Una expresión que permita la asignación de
valores a un elemento de un arreglo.
7Sintaxis abstracta y concreta para la adición de
arreglos al interprete
ltformgt definearray ltvargtltexpgt
definearray (var len-exp) ltexpgt
letarray ltarraydeclsgt in ltexpgt letarray
(arraydecls body)
ltarray-expgtltexpgt arrayref (array index)
ltarray-expgtltexpgt arrayassign (array
index ltexpgt exp) ltarray-expgt ltvarrefgt
(ltexpgt) ltarraydeclsgt ltarraydeclgt
ltarraydecl) decl (var exp)
Un arreglo es una secuencia de celdas las cuales
contienen valores expresados (representación
indirecta) Arreglo Celda(Valor
expresado) Valor expresado Número
Procedimiento Arreglo Valor denotado Celda
(Valor expresado)
8ADT para el arreglo
(define make-array (lambda (length) (let
((array (make-vector ( length 1))))
(vector-set! array 0 'array)
array))) (define array? (lambda (x) (and
(vector? x) (eq? (vector-ref x 0)
'array)))) (define array-ref (lambda (array
index) (vector-ref array ( index
1)))) (define array-set! (lambda (array index
value) (vector-set! array ( index 1) value)))
9ADT para el arreglo
(define array-whole-set! (lambda (dest-array
source-array) (let ((source-len
(vector-length source-array))) (letrec
((loop (lambda (n) (if (lt n
source-len) (begin
(vector-set! dest-array n
(vector-ref source-array n))
(loop ( n 1))))))) (loop
1))))) (define array-copy (lambda (array)
(let ((new-array (make-array (- (vector-length
array) 1)))) (array-whole-set! new-array
array) new-array)))
10Modifs al interprete para manejo de arreglos
(define eval-exp (lambda (exp env)
(variant-case exp (varref (var)
(denoted-gtexpressed (apply-env env var)))
(app (rator rands) (apply-proc
(eval-rator rator env) (eval-rands rands env)))
(varassign (var exp)
(denoted-value-assign! (apply-env env var)
(eval-exp exp env))) (letarray (arraydecls
body) (eval-exp body
(extend-env (map decl-gtvar arraydecls)
(map (lambda (decl)
(do-letarray (eval-exp (decl-gtexp decl) env)))
arraydecls) env)))
(arrayref (array index) (array-ref
(eval-array-exp array env) (eval-exp
index env))) (arrayassign (array index
exp)
(arrayassign (array index exp) (array-set!
(eval-array-exp array env) (eval-exp
index env) (eval-exp exp env))) (else
...))))
11Modifs al interprete para manejo de arreglos
(define eval-rator (lambda (rator env)
(eval-exp rator env))) (define eval-rands
(lambda (rands env) (map (lambda (rand)
(eval-rand rand env)) rands))) (define
eval-rand (lambda (exp env)
(expressed-gtdenoted (eval-exp exp
env)))) (define apply-proc (lambda (proc
args) (variant-case proc (prim-proc
(prim-op) (apply-prim-op prim-op (map
denoted-gtexpressed args))) (closure
(formals body env) (eval-exp body (extend-env
formals args env))) (else (error "Invalid
procedure" proc)))))
12Paso por valor de arreglos (representación
indirecta )
(define denoted-gtexpressed cell-ref) (define
denoted-value-assign! cell-set!) (define
do-letarray (compose make-cell make-array)) (defi
ne eval-array-exp eval-exp) (define
expressed-gtdenoted make-cell)
13Representación de celdas
(define cell-ref (lambda (x) (if (cell? x)
(vector-ref x 1) (error "Invalid
argument to cell-ref" x)))) (define cell-set!
(lambda (x value) (if (cell? x)
(vector-set! x 1 value) (error "Invalid
argument to cell-set!" x)))) (define
cell-swap! (lambda (cell-1 cell-2) (let
((temp (cell-ref cell-1))) (cell-set!
cell-1 (cell-ref cell-2)) (cell-set! cell-2
temp))))
(define cell-tag "cell") (define make-cell
(lambda (x) (vector cell-tag x))) (define
cell? (lambda (x) (and (vector? x)
( (vector-length x) 2) (eq? (vector-ref
x 0) cell-tag))))
14Arreglos representación directa
Arreglo Celda(Número Procedimiento) Valor
expresado Número Procedimiento
Arreglo Valor denotado Celda (Número)Celda
(Procedimiento)Arreglo
En la reprresentación directa cuando un arreglo
es pasado por valor, el parámetro formal es
afectado a una copia de la secuencia de valores.
En caso de que exista una asignación dentro del
procedimeinto, solo la copia local del arreglo se
verá afectada.
15Paso por valor de arreglos (representación
directa )
Habrá que modificar el procedimiento array-set!
de manera a que no pueda existir un arreglo
dentro de otro
(define array-set! (lambda (array index value)
(if (array? value) (error "Cannot
assign array to array element" value)
(vector-set! array ( index 1) value))))
16Paso por valor de arreglos (representación
directa )
(define eval-array-exp eval-exp) (define
expressed-gtdenoted (lambda (exp-val) (if
(array? exp-val) (array-copy exp-val)
(make-cell exp-val))))
(define denoted-gtexpressed (lambda (den-val)
(if (array? den-val) den-val
(cell-ref den-val)))) (define denoted-value-assig
n! (lambda (den-val exp-val) (cond
((not (array? den-val)) (cell-set! den-val
exp-val)) ((array? exp-val)
(array-whole-set! den-val exp-val)) (else
(error "Must assign array" den-val))))) (define
do-letarray make-array)
17Representación indirecta Vs. directa
letarray u3 v2 in begin u0 5 u1
6 u2 4 v0 3 v1 8 let p
proc (x) begin
x1 7 x v x1 9
end in p(u) end
x
u
v
x
u
v
(a)
x
u
x
u
v
v
(b)
18Llamada por referencia
- En Scheme todo tipo de dato se pasa por valor.
- Usa la representación directa para los escalares
tal que los valores numéricos. - Para los agregados usa una representación
indirecta por razones de eficiencia. - En algunas ocasiones es necesario o conveniente
el poder asignar o afectar los valores asociados
a los parámetros con el fin de comunicarle un
resultado al procedimiento llamante. Esto sería
un efecto secundario que a veces es dificil de
entender
19Los alias y el paso por referencia
Algunos problemas provocados por el paso por
referencia los evidencia el siguiente programa
(suponga que los parámetros son pasados por
referencia).
- define swap
- proc (x, y)
- begin
- x (x, y) y -(x, y) x -(x,
y) - end
- ?define b 1
- ?define c 2
- swap(b, c)
- b
- 2
- c
- 1
- swap(b,b)
- b
- 0
20Modelando paso de parámetros por referencia
Para realizar el paso de parámetros por
referencia (en cuanto a variables no del tipo de
arreglos) solamente es necesario cambiar
(define eval-rand (lambda (rand env)
(variant-case rand (varref (var) (apply-env
env var)) (else (error "Invalid operand"
rand)))))
ltoperandgt ltexpgt a ltoperandgt ltvarrefgt
21Modelando paso de parámetros por referencia
- En una implementación típica, el paso por
referencia de un elemento de un arreglo se
realiza a través de un apuntador. - En Scheme no es posible obtener un apuntador a un
elemento de un arreglo (no existe un operador
como en C). - Es necesario crear un nuevo registro para
lograrlo - (define-record ae (array index))
- Nuestros operandos tendrian entonces la siguiente
forma - ltoperandgt ltvarrefgt
- ltarry-expgtltexpgt
- ltexpgt
22Modelando paso de parámetros por referencia
Las siguientes modificaciones a nuetro interprete
son necesarias
(define eval-rand (lambda (rand env)
(variant-case rand (varref (var) (apply-env
env var)) (arrayref (array index)
(make-ae (eval-array-exp array env) (eval-exp
index env))) (else (make-cell (eval-exp
rand env)))))) (define denoted-gtexpressed
(lambda (den-val) (cond ((cell?
den-val) (cell-ref den-val)) ((ae? den-val)
(array-ref (ae-gtarray den-val) (ae-gtindex
den-val))) (else (error "Can't dereference
denoted value" den-val)))))
23Modelando paso de parámetros por referencia
(define denoted-value-assign! (lambda (den-val
val) (cond ((cell? den-val) (cell-set!
den-val val)) ((ae? den-val) (array-set!
(ae-gtarray den-val) (ae-gtindex den-val) val))
(else (error "Can't assign to denoted value"
den-val)))))
24Modelando paso de parámetros por referencia
letarray u3 v2 in begin u0 5 u1
6 u2 4 v0 3 v1 8 let p
proc (x) begin
x1 7 x v x1 9
end in p(u) end
x, u
v
x, u
v
(a)
u
u
v
v
x
x
(b)
25Llamadas por el valor del resultado y llamadas
por resultado
- Es de uso frecuente que el compilador aloje en
localidades específicas (conocidas) de memoria,
los parámetros pasados por valor de manera a que
los procedimientos los accedan de forma directa. - En llamadas por referencia, esto no sucede así y
las localidades específicas no se conocen sino
hasta la propia invocación del procedimiento. - Las llamadas a procedimiento por referencia son
menos eficientes. - Las llamadas por el valor del resultado combinan
- La eficiencia al acceder parámetros que se pasan
por valor. - La habilidad de regresar información via los
parámetros.
26Llamadas por el valor del resultado y llamadas
por resultado
- El parametro que es pasado por llamada por el
valor del resultado es copiado a una localidad
específica de la memoria al momento de la
invocación del procedimiento. - El valor final del parámetro que es pasado por
llamada por el valor del resultado es recopiado a
su localidad original al finalizar el
procedimeinto. - Las llamadas por el valor de resultado son más
eficientes a expensas de un proceso menos
eficiente de invocación y termino de
procedimiento. - Depende de los accesos que el procedimeinto haga
del parámetro en cuestión.
27Llamadas por el valor del resultado y llamadas
por resultado
- El paso por llamadas por el valor del resultado
no sufre de los problemas de alias. - En la ausencia del problema de alias las
llamadas por el valor del resultado tiene el
mismo efecto que las llamadas por referencia. - Normalmente es el compilador quien hace la
elección de que tipo de llamada utilizar. - Las llamadas por resultado tienen las mismas
características que las llamadas por el valor del
resultado excepto que solo se usan para
transferir información del procedimiento llamante
al llamado (ej. Un código de error) - Las llamadas por valor, las llamadas por el valor
del resultado y las llamadas por resultado se
conocen como llamadas por copia.
28Valores expresados o denotados ?
Muchas de las diferencias en los lenguajes de
programación estrivan en el manejo de
- Los valores expresados, los cuales son productos
de la evaluación de una expresión. - Los valores denotados (aquellos valore que
guardamos en memoria) normalmente más ricos que
los expresados - Los valores L-values que aparecen del lado
izquierdo en una asignación.
29Valores expresados o denotados ?...
- En lenguajes imperativos tradicionales las
expresiones ocurren en el lado derecho (R-values)
de las asignaciones. - gt El conjunto de valores expresados
corresponde al conjunto - de valores almacenables en una
localidad de memoria. - En algunos casos es necesario restringir los
valores expresados de manera a evitar
duplicaciones (ej. cunado se representan de
manera directa los agregados)
Ejemplo Valor expresado Numero Valor denotado
L-value Arreglos Procedimientos
30Valores expresados o denotados ?...
- Estudiando los valores expresados y denotados de
un lenguaje proporcionan un profundo conocimiento
de la estructura del lenguaje de programación. - La estructura usada para el almacenamiento y
manejo de los valores por un lenguaje de
programación, determina en buena parte - El poder de expresividad del lenguaje.
- El nivel de eficiencia.
- La estrategia de implementación.
31Llamadas por nombre y llamadas por necesidad.
Algunas LP no evalúan los argumentos antes de
pasarlas a un procedimiento, i.e.retrasan su
evaluación
- No realizar evaluaciones innecesarias.
- Evitar computaciones sin terminación (recuerde el
ejemplo en conversion ?).
32Llamadas por nombre y por necesidad.
- Una de las formas para retrasar la evaluación del
operando es pasar el arbol sintáctico (o codigo
compilado) representando al operando. - De la misma manera que para la definición de los
procedimientos habrá que crear una closure (su
ambiente al momento de definirlo) para cada
argumento. - Los Closures usados para retrasar la evaluación
de los argumentos son conocidos como thunks. - El paso de parámetros en donde la evaluación de
los argumentos es retrasado usando thunk se
conoce como llamadas por nombre. - Almacenando la evaluación (cuando sea necesaria)
de un parámetro para evitar calculo redundannte
se conoce como llamadas por necesidad.
33Argumentos opcionales y por palabra clave
En muchos LP los parámetros formales son
asociados con los argumentos de acuerdo a su
posición El n-esimo parametro formal es
asociado al n-esimo argumento. Es también
posible establecer el paso de los argumentos por
palabra clave tal y como ocurre en muchos
comandos de algunos sistemas operativos (ej. dir
/ad cc l pthread)
- Con operandos por palabra clave es necesario
recordar la palabra clave. - Con operandos por posición es necesario recordar
la posición correspondiente a cada operando
34Argumentos opcionales y por palabra clave
Existen lenguajes de programación que permiten
establecer valores por omisión para ciertos
argumentos.
- conveniente para el caso en que el procedimiento
se llama en repetidas ocasiones con el mismo
valor para ese argumento.
35Argumentos opcionales y por palabra clave
Para el caso de que los argumento que se pasen
por posición es conveniente que los argumentos
opcionales se pongan al final como en el caso de
(lambda (n . m) ). Al utilizar paso de
parámetros por palabra clave y argumentos
opcionales solo se indicarían las palabras claves
de aquellos argumentos obligatorios y de aquellos
cuyo valor por omisión no nos convenga.