bill@ibmpcug.co.uk (Bill Birch) (04/11/90)
Hello, Can anyone refer me to a paper or book about PORTABLE LISP? I want to know if there is a subset of LISP that will work on most dialects of Common LISP, Cambridge LISP, Standard LISP, XLISP, Scheme etc. etc. Perhaps somebody has done a survey to find out what the lowest-common-denominator is? I hope it doesn't turn out to be Pure LISP! Thankyou in advance, Bill Birch -- Automatic Disclaimer: The views expressed above are those of the author alone and may not represent the views of the IBM PC User Group. --
jeff@aiai.ed.ac.uk (Jeff Dalton) (04/11/90)
In article <1990Apr10.170254.610@ibmpcug.co.uk> bill@ibmpcug.co.uk (Bill Birch) writes: > Can anyone refer me to a paper or book about PORTABLE LISP? >I want to know if there is a subset of LISP that will work on most >dialects of Common LISP, Cambridge LISP, Standard LISP, XLISP, Scheme >etc. etc. Perhaps somebody has done a survey to find out what the >lowest-common-denominator is? I hope it doesn't turn out to be Pure LISP! Or greatest common divisor... Sometime in 1985, I looked into this question detail for the main Lisp dialects in use in the UK at the time, namely Franz Lisp, UCI Lisp, Cambridge Lisp, and Common Lisp. If you do this sort of comparison, it soon becomes clear that the common subset that will work without any change or support code in all of these Lisps is fairly small. For example, there isn't a common way to define functions. Franz Lisp and Common Lisp use DEFUN, but UCI Lisp uses DE. (At least one version of Cambridge Lisp allows both, but that doesn't solve the problem in general.) The same sort of thing will happen with your list of dialects. For example, Scheme uses yet another form: DEFINE. On the other hand, if you're willing to write in a somewhat neutral dialect and to write some support code to "adapt" each of the dialects you want your code to run in, you can do much better. For example, you could use DEFUN to define functions provided that you wrote a DEFUN macro for each of the Lisps that use something else. Note that the "neutral dialect" might actually be a subset of some actual dialect, if you are willing to pick a favorite. A problem with this approach, however, is that it is really _too_ powerful. Since the support code (macros and functions that define everything needed by the "portable" neutral-dialect code) can be arbitrarily complex, it's hard to establish clear limits on that the neutral dialect can be. You have to be careful not to be too ambitious, for otherwise you will spend too much time on the support code and may also find that it's difficult to debug anything on the importing side. So this is why I've been calling the portable dialect "neutral": it has to avoid things that work well in only some of the dialects and require elaborate support in all the others. Exactly when support becomes too elaborate is something you'll have to decide. You'll also have to decide whether you really want to include all of the dialects you listed. For example, it may be easier if you leave out Scheme. With those points in mind, here are some of the things that may cause problems: * Functions. It's hard to think of any functions that are exactly the same in every Lisp. Even CAR and CDR can be different, because some Lisps define them for the empty list while others do not. EQ is another function that can vary in its details. You can pretty much rely on its behavior for symbols and conses, but not for numbers and some other things. There are many other examples of this sort. Even if we look instead for functions that have most of their behavior in common, we have a small list, because (for example) Scheme has different names for such things as EQ. (In Scheme it's "EQ?".) * Name conflicts. Since it's not always safe to redefine built-in functions, you have to avoid giving your own functions that same name as any of the built-in function in any of the dialects involved. * Datatypes. Different Lisps support different datatypes. Almost all Lisps will have symbols, conses, and integers up to 16 bits; after that it varies. Strings, vectors, and integers up to the size of the address field of the pointers used by the Lisp (let's say this is usually at least 24 bits) are usually available too. [The latter rule about integers means, more or less, that you can use them to count objects, index vectors, and things like that, but can't rely on such things as 32-bit arithmetic.] Bignums (arbitrarily large integers) are fairly common. * Overlap, disjointness, etc. Some things can turn out to be the same. For example, in some Common Lisps VECTORP is true of the objects defined by DEFSTRUCT. Some predicates, such as ATOM, can vary quite widely. Consequently, you have to be careful about such things as the order of tests in a COND. One of the most important things of this sort is the varying treatment of NIL, false, and the empty list. They might all be different (as they are in some dialects of Scheme) or all be the same (as in Common Lisp). Another important case is that CONSP (or the equivalent) may be true of the functions that result from evaluating lambda-expressions. * Scope and extent. Are variable instances (sometimes called bindings) visible everywhere (indefinite scope) or only within the textual scope of the construct that introduced them (lexical scope)? Are references valid forever (indefinite extent) or only until the construct exits (dynamic extent)? Are lambda-expressions processed with respect to the context in which they occur or as completely separate functions? Since the answers can vary, and since it's difficult to change them very much using support code, neutral code has to try to avoid all of the cases where any of them makes a difference. This pretty much means that free variables can't be used. References to formal parameters that occur within the body of the same function are ok unless they appear inside a lambda- expression, unless the lambda-expression is the car of a function call. Lambda-expressions in the car of a form are usually treated differently from other ones; they're usually treated as would be the equivalent LET. In other contexts lambda-expressions may have to have (FUNCTION ...) around them. So you may want to define a macro, called %LAMBDA or something, that expands into the right thing. * Function and value environments. Common Lisp and a number of other Lisps allow identifiers to act as variables and function names independently. Other Lisps, such as Cambridge Lisp and Scheme do not. Lisps are sometimes referred to as being a Lisp-2 or a Lisp-1, depending on whether function names and variables are different or not, respectively. For example, in Common Lisp (let ((f 10)) (flet ((f (x) (* x x))) (f f))) ==> 100 Moreover, in most Lisp-2s F in (F X) will always be interpreted as a function name. So if F is a function-valued paramater it has ot be called by something like (FUNCALL F X). Another related issue is whether the car of a fucntion application can be any function-valued expression or whether it has to be a name or a lambda-expression. Neutral code has to avoid anything that relies on function names and variables being different, has to call function-valued variables by using FUNCALL (which can then be defined in those Lisps that don't have it), and can't have arbitrary expressions in the function position (ie, the car) of a function call. * Definition syntax, multiple arguments, etc. The syntax for optional and "rest" arguments varies or may have to be built out of lower-level things (eq, LEXPRS). Keyword parameters are pretty much confied to Common Lisp and Lisps that try to approximate CL subsets, such as XLISP. * Control structures. Things like IF, COND, AND, OR, and LET are available everywhere or can easily be defined. Not so things like CATCH, THROW, CALL/CC, and MULTIPLE-VALUE-BIND. * Macros Some Lisps don't have macros, and there isn't yet a standard macro mechanism for Scheme. Jeff Dalton, JANET: J.Dalton@uk.ac.ed AI Applications Institute, ARPA: J.Dalton%uk.ac.ed@nsfnet-relay.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!J.Dalton
kend@tekchips.LABS.TEK.COM (Ken Dickey) (04/12/90)
In article <1990Apr10.170254.610@ibmpcug.co.uk> bill@ibmpcug.co.uk (Bill Birch) writes: >Hello, > Can anyone refer me to a paper or book about PORTABLE LISP? >I want to know if there is a subset of LISP that will work on most dialects of >Common LISP, Cambridge LISP, Standard LISP, XLISP, Scheme etc. etc. >Perhaps somebody has done a survey to find out what the >lowest-common-denominator is? I hope it doesn't turn out to be Pure LISP! > Actually, LISP is a family of languages. This request is like asking for a portable ALGOL (what is the lowest common demoninator between Pascal, Algol68, Scheme, ...?). For single languages (Scheme, CommonLisp, etc) portable implementations exist. Hope this helps... -Ken Dickey