Whilst going over let over lambda I happened across
(defmacro! dlambda (&rest ds)
`(lambda (&rest ,g!args)
(case (car ,g!args)
,@(mapcar
(lambda (d)
`(,(if (eq t (car d))
t
(list (car d)))
(apply (lambda ,@(cdr d))
,(if (eq t (car d))
g!args
`(cdr ,g!args)))))
ds))))
Which they subsequently invoke like so:
(setf (symbol-function 'count-test)
(let ((count 0))
(dlambda
(:inc () (incf count))
(:dec () (decf count)))))
Is there a construct like flet / labels / let that I can bind the resulting closure to, so as to avoid using funcall or the setf symbol-function in a global manner? So I can do something like:
(with-closures ((counter (let ((count 0))
(dlambda
(:inc () (incf count))
(:dec () (decf count))))))
(counter :incf))
You could write a macro:
(defmacro as-functions ((&rest names) &body body)
(assert (every #'symbolp names) () "Names must be symbols")
(let ((args (copy-symbol :args)))
`(flet
,(mapcar (lambda (n) `(,n (&rest ,args) (apply ,n ,args))) names)
,@body)))
For each symbol s
in names
, bind this symbol in the function namespace to the function currently bound by this symbol in the variable namespace. This can shadow any functions already named s
in current lexical scope, but since it is done explicitly, the programmer shouldn't be caught by surprise.
For example:
(let ((a (lambda (u) (+ 3 u)))
(b (lambda (u) (* 2 u))))
(as-functions (a b)
(a (b 3))))
... macroexpands as:
(LET ((A (LAMBDA (U) (+ 3 U))) (B (LAMBDA (U) (* 2 U))))
(FLET ((A (&REST #:ARGS)
(APPLY A #:ARGS))
(B (&REST #:ARGS)
(APPLY B #:ARGS)))
(A (B 3))))
... and evaluates to 9.
Contrary to a binding construct, this can be used with function arguments:
(defun compose (f g)
(as-functions (f g)
(lambda (x) (f (g x)))))
Based from a comment from jkiiski, here is a modified version which accepts (name fun)
bindings in addition to single symbols. This looks like FLET
, except that functions can be computed at runtime.
(defmacro as-functions ((&rest names) &body body)
(let ((args (copy-symbol :args)))
`(flet
,(mapcar
(lambda (name)
(etypecase name
(symbol `(,name (&rest ,args) (apply ,name ,args)))
(cons (destructuring-bind (name fun) name
`(,name (&rest ,args) (apply ,fun ,args))))))
names)
,@body)))
And so:
(defun thing (f g h)
(as-functions (f (k (compose g h)))
(f (k 3))))
Edit: I remembered having read such a macro previously, using MACROLET
: see this reply from Erik Naggum in comp.lang.lisp's Re: Why is Scheme not a Lisp?