Tuesday, March 21, 2006

Lambda Epiphany in C

Today I realized that C can get Lambda like behavior. I wrote the following code:

#include <stdio.h>

int main(void){
  int val = 4;
  int lambfunc(int innerval){
    return innerval+val;
  }
  int i = 2;
  printf("lambfunc(%i) = %i\n",i,lambfunc(i));
  return 0;
}

It gave the following result:

lambfunc(2) = 6

The significance of this is that I was able to write a function in a function that made use of variables in the scope of the function. What was really cool is when I added the nestlamb() function:

#include

int nestlamb(int fn(int)){
  int value = 6;
  return fn(value);
}

int main(void){
  int val = 4;
  int lambfunc(int innerval){
  return innerval+val;
  }
  int i = 2;
  printf("lambfunc(%i) = %i\n",i,lambfunc(i));
  for(val = 0;val < 5; val++)
    printf("nestlamb(lambfunc) = %i\n",nestlamb(lambfunc));
  return 0;
}

What's really cool about this is that I have a function (main) that has a function in it (lambfunc) that uses variables in the local scope. When I go through the loop calling nestlamb() passing lambfunc I call it 5 times with val ranging from 0-4. nestlamb(lambfunc) returns values 6-10. This means that nestlamb uses the changing values in the scope of main. I managed to do this by passing the pointer to lambfunc instead of passing the return value from calling lambfunc(). This passed the pointer to the instance of lambfunc() that exists on the stack. Subtle difference with a powerful result.

Some things to remember when doing this:
  • lambfunc() must only be passed to other functions. Never return it!
  • C has static typing. This still isn't going to be as flexible as things like using (map (lambda) ...) in lisp.
  • You can't declare a lambda and use it in one expression. First you define it, then you use it.


All things considered, this is really cool. I'll be writing some very interesting code in the future. The ability to declare a function on the stack is very interesting to me.

Shaun

2 comments:

Anonymous said...

FWIW

gcc is the only compiler which supports this nested function C extension. Unlike Pascal (lexical scoped local functions) which is simply a syntactic sugar, the gcc implementation uses dynamic scoping which allows one to take the address of such a function ( not possible in Pascal ).

But theres a big gotcha, as the current gcc implementation requires trampolines, which require writing to code segments. This feature has been removed from the OS X version of gcc for the same reason.

Read this blog for more details:
http://ridiculousfish.com/blog/

Regards
Vivek

Tom said...

My first though is of your shirt that says, "I wrote code so you don't have to." My second thought is...never mind, my brains telling me that reading the blog used up the last of my mental capacity allotment for the day. school was a huge drain today.