Sunday, October 24, 2010

LABELS do flow...

On the flight(s) from the ILC meeting (more on that later...), I made a big start on re-writing the code for LABELS (FLET is similar). The original code was just flat wrong (sigh). It would work as long that there were no lexical external bindings. I've redesigned that part of the environment system to properly connect LABELS-defined functions to the rest of the environment. This was a bit tricky due to the rather inelegant "design" of the current compiler. A more elegant environment is in the works, but... I have to put another patch over this gaping hole.

A "smart" environment would have parallel functions for creating lexical bindings (and mechanisms) for values and functions. But the current environment is incapable of working that way. So, here's the kludge (well, it only becomes a kludge if it works, otherwise it's a crock). Example:

(let ((x 42))
  ...
  (labels ((foo (a b) (foo (/ (+ a b) x) nil))
           (bar (x) (* (foo x 13))))
     (foo 1 2))
  ...)

I can't just turn it into a named function by changing the symbol-function slot of foo. Even if I had a mechanism to replace the original function foo, that would be a dynamic binding of foo's function slot. The CL spec requires that the binding is lexical. Making a "real" binding would be very difficult at this point.  But I can use a trick from lambda calculus: renaming.  I change the  form into:


(let ((x 42))
  ...
  (labels ((labels_foo_2883486 (a b) 
             (labels_foo_2883486 (/ (+ a b) x) nil))
           (labels_bar_47927743 (x) (labels_foo_2883486 x 13)))
     (labels_foo_2883486 1 2))
  ...)


The compiler runs through all of the uses of foo and substitutes them with the symbol labels_foo_2883486 d. This is risky because I might miss one. But it's a risk I'll take for now. Note that both foo and bar were renamed, as were all other their uses.

Having renamed all the uses of foo and bar, the compiler is free to treat the renamed foo and bar as top-level functions. Note in both cases, the variable x is lexically visible and correctly used.

Here's what the renamed version of foo and bar if they were built in the scope of an FLET.


(let ((x 42))
  ...
  (flet ((flet_foo_2883486 (a b) (foo (/ (+ a b) x) nil))
         (flets_bar_47927743 (x) (foo x 13)))
     (flet_foo_2883486 1 2))
  ..


Note that the scoping in FLET differs from LABELS.

This kludge works at least in these examples. Nested FLET and LABELS would be problematic.

1 comment:

  1. We have 1 nested Labels that I am currently aware of and that is the GetProperties function in lists.lsp. However, this is one of the list functions I have rewritten. The code is actually only 11 lines now, rather than the older 22 lines it used to have and only has 1 labels defined function rather than the 3 it used to have. Much more efficient.

    ReplyDelete