| With the new fexpr-based interpreter for wart[1] I've been trying to reduce the set of names in the core language and bootstrap complex features by progressive enhancement. For example, I'd like to build arc's if out of a simple two-branch if as follows:  let oldif if
    mac if args
      oldif (no (cdr args))
        (car args)
        `(,oldif ,(car args)
           ,(cadr args)
           (if ,@(cddr args)))
 
But macros must evaluate in the caller's lexical scope.  mac foo(x)
    `(+ ,x 1)
  let y 3
    (foo y) ; must macex to (+ y 1) in foo's scope, then evaluate to 4 in caller scope
 
The solution I'm trying out to get both these macro examples to work is a sort of gracefully degrading lexical scope. At every call, instead of swapping in the callee's environment, I push it above the caller's environment. This is like lexical scope in how bindings override each other:  (let x 3
    def foo()
      (let x 4
        (bar))
    def bar()
      x)
  (foo) ; returns 3 from the outer lexical scope
 
But it also makes the caller's lexical scope available if necessary:  def bar()
    x
  let x 3
    (bar) ; returns 3 like a dynamic scope
 
I haven't seen this idea before, and I'm inclined in this case to think it's probably a bad idea. Can anyone think of use cases where having the extra power bites us? Feel free to play with wart:  $ git clone 
  $ git checkout 4863b4318f
  $ wart
 
One drawback I found was that macros must now almost always use implicit gensyms[1] to avoid overriding bindings in their callers. The correct definition for if in this scheme is:  let $if if
    mac if $args
      $if (no (cdr $args))
        (car $args)
        `(,$if ,(car $args)
           ,(cadr $args)
           (if ,@(cddr $args)))
 
If this macro's parameter was just args it wouldn't have access to any other bindings at macro call-sites using the variable args. It must be a gensym.  if args
    prn "hi" ; requires gensyms in 'if' macro
 
I'm still playing with this to see how onerous it is to have all these $vars in macros. If it's not too onerous, and if we don't discover any other issues, it would mean that I can build macros out of just eval and implicit gensyms and lexical scopes.[1] http://arclanguage.org/item?id=14881, http://github.com/akkartik/wart/tree/unstable [2] http://arclanguage.org/item?id=13342  |