I’ve been thinking about this, and the description of uLisp as (mostly) a subset of Common Lisp that can be found in various places. To what extent is this a significant consideration?
Specifically, I know that
eval in uLisp does not behave the same way it does in Common Lisp. In Common Lisp,
eval does not have access to the current lexical environment, as it is a function. In uLisp, it does. Assuming
x is not defined as a global variable, this means that
(let ((x 1)) (eval 'x)) returns 1 in uLisp, but raises a condition (specifically,
UNBOUND-VARIABLE) in Common Lisp. (If
x is special,
eval can read it, so CL won’t error out.)
Is this to be considered a bug in uLisp, or is it simply a difference in behaviour that the programmer needs to account for? I’m not certain, because there is one aspect of uLisp that is glaringly incompatible with Common Lisp, although most of the time it can be papered over. uLisp is a Lisp-1, while Common Lisp is a Lisp-2. This means that you can do things in uLisp that Common Lisp can’t quite keep up with. For a demonstration:
(let ((x (lambda () 1))) (x))
This code will run fine in uLisp. It will cause an error in Common Lisp, or worse, call a different function. One way of keeping to the concept that uLisp code should run fine in Common Lisp here is to simply say that uLisp doesn’t support lexically scoped functions, and having the evaluator only search the global environment for functions - but at that point, it really is a sort of Lisp-2, it just happens that the function value is always the same as the normal value.
To loop back to the initial question, I’m not saying that uLisp code must be able to run in Common Lisp. I’m wondering to what extent the ability to do so should decide what uLisp does - because to the extent uLisp allows things Common Lisp doesn’t, it isn’t a subset, and in that case it would be good to know which differences are intentional and which are accidental.