Hacker News new | ask | show | jobs
by kazinator 1366 days ago
We can analyze lexical scoping through quote. Here is TXR Lisp doing it:

  1> (defmacro free-vars (expr :env e)
       (if-match (quote @qexp) expr  ;; unwrap quote if it occurs
         (set expr qexp))
       (tree-bind (expansion free-vars free-funs . rest) (expand-with-free-refs expr e)
         ^(quote ,free-vars)))
  free-vars
  2> (let ((a 42)) (free-vars '(lambda () (+ a b))))
  (b)
Roughly speaking, this is the basis for doing things like back-referencing against an existing lexical variable in pattern matching:

  3> (let ((x 1))
       (match (@x @y) '(1 2) y))
  2
  4> (let ((x 1))
       (match (@x @y) '(2 2) y))
  ** match: (@x @y) failed to match object (2 2)
match is nothing but a macro; application code could supply an equivalent, depending only on what is publicly documented.

Syntactically, the variable terms in (@x @y) are in the same category. Yet x is interpreted by the pattern matcher as a bound variable, whose value matches the corresponding object; whereas y is interpreted as a free variable to be lexically bound to the corresponding object.

You just need a macro system with environment parameters, and a defined API into them.

With help from the macro system, we could write an interpreter such that (let ((a 1) (b 2)) (interpret '(list a b))) will yield (1 2). interpret can't be a function; it has to be a macro which analyzes the argument for variables and creates a bridge between those variables and the surrounding lexicals at the point where interpret finds itself. The interpret macro transforms the code somehow and then hands it to an interpreter function.