Ejemplo de Paso por Referencia¶
Suponga paso por referencia para la siguiente expresión:
let
f = proc(x) ; Procedimiento que duplica su argumento por referencia
begin
set x = *(2, x); ; Modifica la variable referenciada por x, duplicando su valor
x ; Retorna el nuevo valor de x
end
g = proc(u, v) ; Procedimiento que aplica v a u y suma el resultado a u
begin
set u = +(u, (v u)); ; u = u + (v aplicado a u). v debe ser un procedimiento.
u ; Retorna el nuevo valor de u
end
in
let
a = 10
b = 20
in
+((g a f), (g b f)) ; Suma el resultado de aplicar g a 'a' y a 'b' con 'f'
Resultado: 90
graph TD
A["empty-env"] --> B["env1
f g
dt(closure empty-env) dt(closure empty-env)
"]
B --> C["env2
a b
dt(10 --> 20) dt(20 --> 40)"]
A --> G1["envg1
u v
id(a) id(f)"]
A --> F1["envf1
x
id(a)"]
A --> G2["envg2
u v
id(b) id(f)"]
A --> F2["envf2
x
id(b)"]
Evaluación Paso a Paso (Paso por Referencia)¶
- Primera llamada
(g a f): Se crea el ambienteG1dondeues una referencia aa(valor 10) yves una referencia af. -
En
G1se evalúa+(u, (v u)): El orden de evaluación es de izquierda a derecha.- Primero se evalúa
u→ 10. - Luego se evalúa
(v u)→ esto es(f a).- Se crea el ambiente
F1dondexes una referencia aa. - Se ejecuta
set x = *(2, x): Esto modifica la celda a la que apuntanxya, cambiando su valor de 10 a 20. fretorna el nuevo valor dex(que es el dea): 20.
- Se crea el ambiente
- Ahora en
G1podemos resolver+(10, 20) = 30. - La asignación
set u = 30modifica la celda deaa 30.gretorna 30. - Estado actual:
a = 30,b = 20.
- Primero se evalúa
-
Segunda llamada
(g b f): Se crea el ambienteG2dondeues una referencia ab(valor 20) yves una referencia af. -
En
G2se evalúa+(u, (v u)):- Primero se evalúa
u→ 20. - Luego se evalúa
(v u)→ esto es(f b).- Se crea el ambiente
F2dondexes una referencia ab. - Se ejecuta
set x = *(2, x): Esto modifica la celda deb, cambiando su valor de 20 a 40. fretorna 40.
- Se crea el ambiente
- En
G2resolvemos+(20, 40) = 60. - La asignación
set u = 60modifica la celda deba 60.gretorna 60. - Estado final:
a = 30,b = 60.
- Primero se evalúa
-
Evaluación final en
env2: Se calcula+((g a f), (g b f))→+(30, 60)= 90.
Importancia del Orden de Evaluación¶
PILAS: Si cambiamos +(u, (v u)) por +((v u), u) en la definición de g, el resultado sería 120. Esto demuestra que el orden de evaluación de los sub-expresiones con efectos laterales afecta el resultado final.
Explicación del cambio:
Con +((v u), u) en (g a f):
1. Primero se evalúa (v u) ((f a)), que cambia a de 10 a 20 y retorna 20.
2. Luego se evalúa u, que ahora vale 20.
3. La suma es +(20, 20) = 40, y a queda en 40.
Un proceso similar para b llevaría a b = 80. La suma final sería +(40, 80) = 120.
Tabla de Resumen de Conceptos¶
| Concepto | Descripción | Implicación en el Ejemplo |
|---|---|---|
| Paso por Referencia en Llamadas | Los parámetros u y v en g, y x en f, reciben referencias a las variables del llamador (a, b, f). |
Las modificaciones con set dentro de f y g afectan directamente a a y b en el ambiente exterior. |
| Aliasing | Múltiples nombres (u en G1 y x en F1) se refieren a la misma celda mutable (a). |
Un cambio a través de un alias (x) es visible inmediatamente a través del otro (u). |
| Orden de Evaluación | El orden en que se evalúan los operandos de una operación (ej., +) es crucial cuando estos tienen efectos laterales. |
Cambiar de +(u, (v u)) a +((v u), u) produce resultados diferentes (90 vs 120) porque cambia el momento en que se lee el valor de u. |
| Efectos Laterales Acumulativos | Un procedimiento puede modificar su argumento, y ese cambio persiste para futuras operaciones. | f modifica su argumento, y ese valor modificado es usado luego en la suma dentro de g. |
| Procedimientos como Argumentos | Un procedimiento (f) puede pasarse como argumento a otro procedimiento (g). |
Esto permite una gran flexibilidad. g es un procedimiento de orden superior que aplica un procedimiento v a su argumento u. |
| Estado Mutable Global | El estado de las variables a y b evoluciona a lo largo de la evaluación completa del programa. |
No podemos entender el valor de (g a f) solo mirando su código; debemos rastrear el historial de modificaciones de a. |
Comentarios Adicionales sobre el Tema¶
- Depuración Compleja: Programar con paso por referencia y efectos laterales hace que el flujo de datos sea menos obvio. Depurar requiere rastrear no solo el valor de las variables, sino también qué alias existen para ellas en cada punto del programa.
- Semántica Definida del Lenguaje: El ejemplo subraya por qué los lenguajes de programación deben definir explícitamente su orden de evaluación (e.g., izquierda-a-derecha, derecho-a-izquierda, no especificado). En lenguajes con efectos laterales, un orden no especificado puede llevar a resultados no portables.
- Diseño de APIs: Al diseñar procedimientos que modifican sus argumentos (como
fyg), es una buena práctica documentar claramente este comportamiento. Muchos estilos de programación modernos prefieren evitar la modificación de argumentos y, en su lugar, retornar nuevos valores, para hacer el código más predecible y fácil de razonar. - Optimizaciones y Efectos Laterales: Los compiladores tienen dificultades para optimizar código con efectos laterales impredecibles. Por ejemplo, no pueden reordenar ni eliminar llamadas a procedimientos si no pueden probar que son libres de efectos laterales (que no modifican estado observable).