There exists

I responded to a Clojure job posting last winter and had the pleasure of using it for the coding exercise. The job wound up actually being a 100% Python position (why do people do this) but the language left a very positive impression on me. While I will never use it for a personal project (JVM), I'd love to incorporate its elements into my scheming.

Take let for example. In Scheme you have to do

(let ((x 1) (y 2)) (+ x y))


(let* ((x 1) (y (+ x 1))) (+ x y))

if you'd like to reference other bindings. Compare that to

(let [x 1 y (+ x 1)] (+ x y))

from Clojure.

This is Lisp we're talking about, so I don't mind parentheses, but there's definitely room for significant whitespace here and there, especially for something as basic as binding variables. Luckily enough it's easy to write a syntax-rules macro that provides this functionality—without the stupid square brackets too.

(let ((x 2)) (* x x))

is of course functionally equivalent to

((lambda (x) (* x x)) 2)

and the earlier example of let* actually compiles to

((lambda (x) ((lambda (y) (+ x y)) (+ x 1))) 1)

Getting the desired assignment behavior means iterating across the variable/value list, recursively creating closures with the variables, which take their respective values as their sole argument. Each subsequent lambda retains the scope of the previous assignment, giving the final procedure access to every value.

With syntax-rules, the pattern of "variable, value, and maybe some more pairs" is encoded as

(α β ω ...)

where ω ... could be any number of additional bindings, including zero.

This means that the whole syntax can be matched as

(_ (α β ω ...) f ...)

where f ... is the final procedure(s) that will operate on all the bindings.

In order to retain traditional let syntax, I've called this macro (Vim digraph TE), for "there exists."

(define-syntax ∃
  (syntax-rules ()
    ((_ () f ...)          (begin f ...))
    ((_ (α β ω ...) f ...) ((lambda (α) (∃ (ω ...) f ...)) β))))

The recursion should be straightforward; once there are no more bindings, run the functions. Until that happens, create closures and recursively call on the remaining items.

> (∃ (x 1 y (+ x 1)) (+ x y))

I think this looks better than Scheme's and Clojure's syntax.