Los procedimientos son parte elemental de los lenguajes de programación, permiten ejecutar código que se repite.
Para implementar lo procedimientos vamos a incluir en la gramática lo siguiente:
<expression> ::= "proc" "(" (<identifier>* (,)) <expression> (proc-exp)
::= "(" <expression> <expression>* ")" (app-exp)
De acuerdo a esto vamos a poder ejecutar cosas como
let
f = proc(x,y) +(x,y)
in
+((f 1 2), (f 1 3)) ; 7
Esto permite ejecutar procedimientos los cuales permiten reutilizar código de tal forma enviamos los parámetros, sin embargo tenemos un problema
let
f = proc(a,b) +(a,b,x)
in
let
y = (f 1 2) ; +(1,2,1) = 4
x = 12
in
(f 1 2) ; (1,2,12) = 15
Para resolver esto introducimos el concepto de la clausura o procVal
Esto permite representar un procedimiento como un valor, la clausura contiene:
- Los identificadores del procedimiento
- El cuerpo del procedimiento
- El ambiente donde fue creado para garantizar consistencia
(define-datatype procVal procVal
(closure
(lid (list-of symbol?))
(exp expression?)
(old-env environment?)
)
)
)
- Valores denotados Numeros + Booleanos + Procval
- Valores expresados Numeros + Booleanos + Procval
; Closure ; Representación de los procedimientos (define-datatype procVal procVal? (closure (lid (list-of symbol?)) (exp expression?) (old-env enviroment?) ))
Modificaciones a la gramática¶
(expression ("proc" "(" (separated-list identifier ",") ")" expression) proc-exp)
(expression ("(" expression (arbno expression) ")") app-exp)
Modificaciones a eval-expression¶
(proc-exp (lid exp)
(closure lid exp env))
(app-exp (rator rands)
(let
(
(procv (eval-expression rator env))
(vrands (map (lambda (x) (eval-expression x env)) rands))
)
(if
(and
(procVal? procv)
(= (length (procVal->lid procv))
(length vrands))
)
(cases procVal procv
(closure
(lid exp old-env)
(eval-expression exp
(extend-env lid vrands old-env))))
(eopl:error "Not a procedure or incorrect of number of args"))
)
)
Ejemplo¶
Suponiendo el ambiente del interpretador
let
x = 10
y = +(x,y)
z = +(z,y)
f = proc(a,b,c) +(a,*(b,c))
in
(f x y z)
---
config:
flowchart:
htmlLabels: false
---
flowchart LR
E["Empty-env"]
B["env1
x,y,z
1,2,3"]
A["env0
a,b,c
4,5,6
"]
C["env2
x,y,z,f
10,3,5, closure(...,env1)
"]
D["envf
a,b,c
10,3,5"
]
E --> A
A --> B
B --> C
B --> D