In Lisp and Scheme
In Lisp family languages such as Common Lisp, Scheme, and others, functions are objects, just like strings, vectors, lists, and numbers. A closure-constructing operator creates a function object from a part of the program: the part of code given as an argument to the operator is part of the function, and so is the lexical environment: the bindings of the lexically visible variables are captured and stored in the function object, which is more commonly called a closure. The captured bindings play the role of member variables, and the code part of the closure plays the role of the anonymous member function, just like operator in C++.
The closure constructor has the syntax (lambda (parameters ...) code ...)
. The (parameters ...)
part allows an interface to be declared, so that the function takes the declared parameters. The code ...
part consists of expressions that are evaluated when the functor is called.
Many uses of functors in languages like C++ are simply emulations of the missing closure constructor. Since the programmer cannot directly construct a closure, they must define a class that has all of the necessary state variables, and also a member function. Then, construct an instance of that class instead, ensuring that all the member variables are initialized through its constructor. The values are derived precisely from those local variables that ought to be captured directly by a closure.
A function-object using the class system, no use of closures:
(defmethod functor-call ((c counter))
(incf (value-of c)))(defun make-counter (initial-value)
(make-instance 'counter :value initial-value))- use the counter
(defvar *c* (make-counter 10)) (functor-call *c*) --> 11 (functor-call *c*) --> 12
Since there is no standard way to make funcallable objects in Lisp, we fake it by defining a generic function called FUNCTOR-CALL. This can be specialized for any class whatsoever. The standard FUNCALL function is not generic; it only takes function objects.
It is this FUNCTOR-CALL generic function that gives us function objects, which are a computer programming construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. We have almost the same syntax: FUNCTOR-CALL instead of FUNCALL. Some Lisps provide funcallable objects as a simple extension. Making objects callable using the same syntax as functions is a fairly trivial business. Making a function call operator work with different kinds of function things, whether they be class objects or closures is no more complicated than making a + operator that works with different kinds of numbers, such as integers, reals or complex numbers.
Now, a counter implemented using a closure. This is much more brief and direct. The INITIAL-VALUE argument of the MAKE-COUNTER factory function is captured and used directly. It does not have to be copied into some auxiliary class object through a constructor. It is the counter. An auxiliary object is created, but that happens behind the scenes.
(defun make-counter (value) (lambda (incf value))) ;;; use the counter (defvar *c* (make-counter 10)) (funcall *c*) ; --> 11 (funcall *c*) ; --> 12Scheme makes closures even simpler, and Scheme code tends to use such higher-order programming somewhat more idiomatically.
(define (make-counter value) (lambda (set! value (+ value 1)) value)) ;;; use the counter (define c (make-counter 10)) (c) ; --> 11 (c) ; --> 12More than one closure can be created in the same lexical environment. A vector of closures, each implementing a specific kind of operation, can quite faithfully emulate an object that has a set of virtual operations. That type of single dispatch object-oriented programming can be done fully with closures.
Thus there exists a kind of tunnel being dug from both sides of the proverbial mountain. Programmers in OOP languages discover function objects by restricting objects to have one main function to do that object's functional purpose, and even eliminate its name so that it looks like the object is being called! While programmers who use closures are not surprised that an object is called like a function, they discover that multiple closures sharing the same environment can provide a complete set of abstract operations like a virtual table for single dispatch type OOP.
Read more about this topic: Function Object
Famous quotes containing the words lisp and/or scheme:
“Taught me my alphabet to say,
To lisp my very earliest word,”
—Edgar Allan Poe (18091849)
“Television programming for children need not be saccharine or insipid in order to give to violence its proper balance in the scheme of things.... But as an endless diet for the sake of excitement and sensation in stories whose plots are vehicles for killing and torture and little more, it is not healthy for young children. Unfamiliar as yet with the full story of human response, they are being misled when they are offered perversion before they have fully learned what is sound.”
—Dorothy H. Cohen (20th century)