Book recommendation: Let Over Lambda—50 Years of Lisp by Doug Hoyte
My starting point is Derek Feichtinger’s discussion and the official C, C++, D
Source Code Blocks in Org Mode. Considering how much boilerplate there is to C
code, Org Babel does a decent job in bringing some literacy to the picture. We
get noweb syntax, can pass variables by header arguments, and can CALL
source
blocks as functions. However, an unpleasant side-effect of those parameters is
the creation of global variables in the tangled C code, which makes me
uncomfortable. (OCD?)
In C, nothing prevents us from reducing some boilerplate through a strict
block-local variables discipline. From the perspective of structuring a larger
piece of C code that’s not sufficient though, because it casts a shadow of
obscurity over code blocks due to potential references to variables outside the
block scope. Looking at a noweb reference such as <<block>>
, I can’t really
tell which variables from the current lexical scope it references. Conversely,
when implementing the code behind <<block>>
, I don’t remember anymore what is
in referents’ scope. Ideally, there would be a way to pass arguments, and there
is, but the price, currently, are global variables. They say that we can’t have
λ-functions in C, but what’s holding us back?
For this collection, we’ve wrapped standard headers and macros into a single header file called literate-hdf5.h.
These are the standard header files included.
#include "hdf5.h"
#include <stdio.h>
#include <stdlib.h>
The more interesting bit is the lambda
macro by Al Williams.
#define lambda(lambda$_ret, lambda$_args, lambda$_body) \
({ \
lambda$_ret lambda$__anon$ lambda$_args \
lambda$_body \
&lambda$__anon$; \
})
It uses two features of GNU C (--std=gnu99
), namely, nested functions and
statement expressions, which lets us wrap C code blocks as “lambda functions”,
thereby making longer pieces of code easier to follow and digest.
lambda(<return type>, ([type1 arg1, type2 arg2, ...]), { <lambda body> })
Such a lambda
can then be invoked like a C-function pointer:
#include "literate-hdf5.h"
int main()
{
unsigned majnum, minnum, relnum;
H5get_libversion(&majnum, &minnum, &relnum);
printf
("%f\n",
(*lambda(float, (float x), { return x*x; })) (majnum+minnum+relnum)
);
return 0;
}
196.0
I can live with that, because now I can break this up into:
#include "literate-hdf5.h"
int main()
{
unsigned majnum, minnum, relnum;
H5get_libversion(&majnum, &minnum, &relnum);
printf
("%f\n",
(*
<<lambda-square>>) (majnum+minnum+relnum)
);
return 0;
}
196.0
and
lambda (float, (float x),
{
return x*x;
})
No global variables and no obscure references!