[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

a brief introduction to "closures" for "uneducated" C hackers




1. Apologies if the term "uneducated" offended anyone. 

   As you may understand from my post on "Programming languages matter", I
   believe that the computer science culture is deteriorating faster than
   moldy yogurt or whatever. I am deeply saddened by the lack of general PL
   education that I see in the general programmer population. 

   The very fact that you have signed up for a Scheme mailing list shows
   that you attempt to learn things about the general area, and a pretty
   advanced language on top. So the term wasn't meant as an insult to the
   people on this list, but rather as a descriptive term concerning the
   people in the programming/SE world. 

2. A closure is function that knows its lexical scope. 

   Consider this quasi-C program: 

     [double -> double] d_dx( [double -> double] f ) {

	// a locally defined constant 
	double epsilon = 0.000001

	// a locally defined procedure [not C] 
	double f_prime(double x) { 
	   return ( ( f(x + epsilon) - f(x - epsilon) )
		    / 
		    (2 * epsilon) ) 
	}; 

	// d_dx's true body: [not C]
	return f_prime; 
      }

    The notation [double -> double] is the type of a function that consumes
    a double and returns a double. So, d_dx is a function that consumes such 
    a beast and returns one, too. 

    We could use it as follows: 

    main() {
      double epsilon = 0.1; 
      [double -> double] f_prime = d_dx(sin); 

      printf("\d\n", f_prime(0.0)); 
      printf("\d\n", f_prime(0.0+epsilon)); 
      printf("\d\n", f_prime(0.0+epsilon+epsilon)); 
    }


    The function f_prime is a closure. d_dx, sin, cos, and so on are just
    functions. The difference is that f_prime's definition refers to two
    variables in its lexical context: epsilon and f.  

    A Scheme compiler knows how to emit code that constructs a value that
    represent f_prime properly, meaning, the epsilon w/i d_dx not the one 
    that is defined in the context of one of d_dx's many "users". 

    LISP, and for a long time Smalltalk, got this all wrong. 

    In C, you can't define functions in a lexically nested position. So the
    problem didn't come up. 

3. The above example doesn't explain the true power of closures. For that,
   read SICP, HtDP, or Concrete Abstractions or any other Scheme book. 

Hope this helps  -- Matthias