Programming Languages: Chapter 11: Functions and Closures



Adding functions to ChAmElEoN

  • two new production rules and constructors on [EOPL2] p. 84
  • sample expression on [EOPL2] p. 84
  • we want functions to be first class objects in the defined language
  • therefore, we want expressed value = denoted value = number ∪ closure
  • what information must we include in the value of a function?
  • in order to determine this, let us examine what happens at function-application time


Closures

  • when a funcation is applied, its body is evaluated in an environment which binds the formal parameters to the actuals and binds the free variables in the body to their values in the enclosing environment at the time the funcation was created (called static scoping)
  • see example on [EOPL2] p. 85
  • when f is called, its body should be evaluated in the following environment: {(y,2), (z, 28), (x,5)}
  • ``in order for a function to retain the bindings of its free variables at the time it was created, it must be a closed package, [completely] independent of the environment in which it is used'' [EOPL2] p. 85
  • this package is called a closure
  • a closure must contain:
    • the body of the function
    • the evaluation environment
      • binding of formal parameters to actual parameters
      • the bindings of its free variables from enclosing environment
  • a closure is a (code, environment) or (code, state) pair; remind you of an object in object-oriented programming?
  • every language has closures, but only some (e.g., Scheme) give the programmer access to them (i.e., closures are only first-class entities in some languages)
  • ``we say that this function is closed over or closed in its creation environment'' [EOPL2] p. 85
  • therefore, let us think of a function value as an ADT with the following interface:
    • make-closure (builds a function value)
    • apply-closure (applies a function value)
  • must satisfy the following equation:
    (apply-closure (make-closure parameters body environ) arguments) =
    (evaluate-expr body (extend-environment parameters arguments environ))
    
  • closure representation
    • Scheme closure representation on [EOPL2] pp. 85-86
    • abstract syntax representation on [EOPL2] pp. 86


Augmenting evaluate-expr

  • now with this foundation in place, we can easily modify our interpreter to handled first-class functions
  • new code for evaluate-expr on [EOPL2] p. 87
  • augmented evaluate-expr in Fig. 3.7 on [EOPL2] p. 88
  • sample expression evaluation example on [EOPL2] pp. 88-89
  • again, identifiers for variables need not appear in syntax trees manipulated by an interpreter [EOPL2]
  • if we use the ribcage representation for an environment, then the lexical address of a variable reference v (d p) tells us exactly where the variable reference appears: the d-th rib at position p [EOPL2]


eval/apply in Scheme

    eval and apply are the heart of any interpreter.

    eval is the Scheme primitive analog of eval-expression procedure in your interpreter. eval takes an expression and environment as arguments.
    ;; (define f (lambda (x) (cons x ())))
    (define f (list 'lambda '(x) (list cons 'x '())))
    ((eval f) 5)
    
    eval enables meta-programming (i.e., the ability to write programs which write and evaluate other programs).

    apply is the Scheme primitive analog of the family of apply-* evaluate-expr procedures in your interpreter (e.g., apply-primitive, apply-closure, and so on). apply takes a procedure and its arguments as arguments.
    (apply + '(1 2 3))
    



    (regenerated with minor modifications from [SICP] Fig. 4.1, p. 364)


Adding recursion to ChAmElEoN

  • new production rule and constructor on [EOPL2] p. 93
  • sample programs on [EOPL2] p. 93
  • we will evaluate the body of a recursive procedure in a recursively-extended environment (see Fig. 3.8 on [EOPL2] p. 94)
  • behavior of recursively-extended environment on [EOPL2] p. 93
  • we use Scheme's letrec itself to recursively extend a procedurally-represented environment
    • involves packaging up an instance of the closure data type
    • see [EOPL2] Fig. 3.9 on p. 95
  • we can represent a recursively-extended environment using abstract syntax as well
    • involves adding a new variant to the environment data type,
    • adding a extend-environ-recursively procedure, and
    • adding a new case to apply-env which packages up an instance of the closure data type
    • see [EOPL2] Fig. 3.10 on p. 96
  • notice that in each of the above recursively-extended environment representations, ``we build a new closure each time a procedure is retrieved from the environment'' [EOPL2] p. 95
  • ``this is unnecessary since the environment for the closure is always the same'' [EOPL2] p. 95
  • ``if we use a ribcage representation of the environment, we can build the closures only once, by building an environment with a circular structure'' [EOPL2] p. 95
    • return to the original environment representation (that without the recursively-extended-envitron-record variant)


    • (regenerated from [EOPL2] Fig. 3.11 on p. 97)

    • see code for extend-environ-recursively in [EOPL2] Fig. 3.12 on p. 97
      • use of vector-set! (function built into Scheme)
      • use of for-each (function built into Scheme)
      • use of iota (function not built into Scheme)


Chapter Summary: the BIG picture

  • we have so carefully designed our ADTs through interfaces that now our interpreter is flexible
  • programming language concepts (on which this course focuses) often have options:
    • scoping (static or dynamic)
    • binding (deep, shallow, ad-hoc)
  • we can often alter the semantics of the defined language drastically (e.g., from static to dynamic scoping) by changing as little as 1-2 lines of code in the interpreter (usually just change how and when we pass the environment) (e.g., deep, shallow, or ad-hoc binding approaches).
  • again, identifiers for variables need not appear in syntax trees processed by an interpreter (depth and position are all we need)
  • in summary, the interpreter for a computer language is nothing more than another computer program [EOPL2] Forward


References

    [EOPL2] D.P. Friedman, M. Wand, and C.T. Haynes. Essentials of Programming Languages. MIT Press, Cambridge, MA, Second edition, 2001.
    [SICP] H. Abelson and G.J. Sussman. Structure and Interpretation of Computer Programs. MIT Press, Cambridge, MA, Second edition, 1996.

Return Home