Common LISP has turned any Function a Symbol holds, into An Additional Field.

I had started to write about this subject some time ago.

This was a posting of mine, in which I pondered the more-general question, of how different LISP variants may recognize, that they have encountered a List or an Atom.

In this posting, I went into the specific question more, of how to use Common LISP, and manipulate the distinction between Symbols that store Functions, and Symbols that store Lists. Obviously, Common LISP requests, that we use the built-in function (symbol-function) to refer specifically to the Function stored within.

And in this posting, I carried out a very basic experiment, to see whether a data-type is stored on the plist, in Common LISP. The answer was No.

I should not even refer to my experiments as such, because they are too rudimentary to qualify. Instead, these are simple efforts to educate myself – and anybody else who might be curious enough to read my blog – about LISP, through Common LISP. Testing the plist of a Symbol, is very straightforward in practice.

I have gone further with the present posting, by just confirming what I already suspected. When we use a Symbol to store a Function, in fact this gets treated separately, and again does not get stored on the plist. The function-field could state that the Symbol stores a Compiled Function, or a List that needs to be Interpreted, according to which blocks of addresses it points to…

What I have noticed however, is that in the case of Predefined, Compiled Functions, meta-data does get stored on the plist, which allows the LISP Compiler to act more, as Compilers do, for languages intended to be procedural in style. LISP was originally intended for declarative-style programming, but to be able to compile each function, it was necessary to standardize the way parameter-lists work, as well as return-types, conform to how they work in procedural languages such as C or C++.

In keeping with that, the plist of a Compiled, Predefined, Common LISP Function, contains templates, that state expected parameter-type-lists, just as C Function-Prototypes would have it.

But what seems to follow, is a flavor of LISP, which does not require the plist, in order for images to execute, and in order to be able to evaluate Lists. They only seem to be needed, to develop images and ‘LISP-Programs’.

The following code block shows, what happened in my most recent session…

 



GCL (GNU Common Lisp)  2.6.12 CLtL1    Oct 28 2014 10:02:30
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License:  GPL due to GPL'ed components: (XGCL READLINE UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/

>(setf (symbol-function 'arbit-fun)
    #'(lambda (pos-arg1 pos-arg2)
        (list pos-arg1 pos-arg2) ) )

(LAMBDA-CLOSURE () () () (POS-ARG1 POS-ARG2) (LIST POS-ARG1 POS-ARG2))

>(arbit-fun 'Foo 'Blatz)

(FOO BLATZ)

>(arbit-fun 'Ergo 'Sum)

(ERGO SUM)

>(symbol-plist 'arbit-fun)

NIL

>(symbol-plist 'list)

(COMPILER::INLINE-ALWAYS
    (((T T T T T T T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T T T T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T T T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T T) T 1 COMPILER::LIST-INLINE)
     ((T T T) T 1 COMPILER::LIST-INLINE)
     ((T T) T 1 COMPILER::LIST-INLINE) ((T) T 1 "make_cons(#0,Cnil)")
     (NIL T 0 "Cnil"))
    COMPILER::RETURN-TYPE T COMPILER::ARG-TYPES (*) COMPILER::LFUN
    "Llist" SYSTEM::TYPE-PREDICATE LISTP)

>(quit)


 

The astute reader may notice, that when LISP programmers use (defun), they are given no mechanism to constrain the parameter-types. Therefore, there should be no need for such plist entries for (defun) functions either, where any type-checking happens in the underpinnings, provided by the predefined functions. So, this little snippet confirms it:

 



>(defun arbit-fun2 (pos-arg1 pos-arg2)
    (list pos-arg1 pos-arg2) )

ARBIT-FUN2

>(arbit-fun2 'Foo 'Blatz)

(FOO BLATZ)

>(symbol-plist 'arbit-fun2)

NIL

>(symbol-function 'arbit-fun2)

(LAMBDA-BLOCK ARBIT-FUN2 (POS-ARG1 POS-ARG2) (LIST POS-ARG1 POS-ARG2))

>(arbit-fun2 'Foo 'Blatz)

(FOO BLATZ)

>(symbol-function 'list)

#<compiled-function LIST>

>(setq arbit-fun2 'Ergo)

ERGO

>arbit-fun2

ERGO

>(arbit-fun2 'Foo 'Blatz)

(FOO BLATZ)

>(quit)


 

I think that I should also mention, how (setf) behaves differently from (defun) and (defvar) and (defparameter), when it comes to returned Lists. (setf) and its brothers return the Value which has been assigned to assumed, dynamically-bound Variables. OTOH, (defun) and (defvar) return the Names of lexically-bound variables instead of their Values.

(Edit 10/02/2016 : )

Evidence would have it, that with Common LISP, even though the behavior of (setf) and (setq) is slightly different from that of (defvar) and (defparameter), all their Symbols seem to be lexically bound, even if they are intended for dynamically-bound use. The only ones which are not, seem to be the ones created using (let) or (let*).

Also, this affects how the quoting mechanism works, even though it takes place while scanning the input-line.

This seems to suggest that a central table is maintained by the LISP session, which allows for any Symbol-names to be matched, that were parsed within the same session, yielding addresses.

 


GCL (GNU Common Lisp)  2.6.12 CLtL1    Oct 28 2014 10:02:30
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License:  GPL due to GPL'ed components: (XGCL READLINE UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/

>(progn (setq var1 'Bar)
    NIL )

NIL

>(progn (setq var2 'Bar)
    NIL )

NIL

>(eq var1 var2)

T

>(list var1 var2)

(BAR BAR)

>


 

Yet, the question has nagged me persistently, of where Common LISP might store the (symbol-name), back from the Symbol itself. Reverse-lookups in tables tend to be costly for the CPU to execute.


 

And so another concept which I might introduce, is the fact that in LISP, there exists a type of object, which is even more primitive than a Symbol.

According to the earliest concepts in LISP – which was invented in the late 1960s – there were only supposed to be Lists and Atoms, where each element of a List could be another List, or an Atom. It was already a concept in the beginnings of the language, that an Atom could hold another Value, and so it seems to make most sense to assume that Atoms correspond to the concept of Symbols today.

A Symbol can have a Name which is independent of its assigned Value, the latter of which could be a List, or another Symbol, or by which a Symbol can even point to itself as Value.

But there also exists the concept today, of a Datum. Differently from how it is with Symbols, a Datum can point to a variable-length data-type, such as a string or variable-length integer, as well as to the actual Value, but its only name is synonymous with the Value, or with what would be printed out, to represent its Value. It cannot point back to other objects, such as Lists or Symbols.

The existence of a Datum explains why it is possible to have a string, or a number, occur as an argument to a Function, before the Function assigns it to a Symbol.

And so this realization can lead to some speculative thinking.

If a Symbol can point to a Datum, the latter of which has no Name, this can simplify the representation of Symbols, because it would mean that the Symbol does not need to point to any data-type, only to a List or another Symbol, or a Datum.

It would also mean that where a Symbol was using an extra field, to store a plist, as well as maybe a back-reference after all, to its Name, that field could get used by a Datum instead, to store its data-type, in the form of a data-type-Symbol,?

 



GCL (GNU Common Lisp)  2.6.12 CLtL1    Oct 28 2014 10:02:30
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License:  GPL due to GPL'ed components: (XGCL READLINE UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/

>(deformed-symbol)

Error: UNDEFINED-FUNCTION :NAME DEFORMED-SYMBOL
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by EVAL.
UNDEFINED-FUNCTION :NAME DEFORMED-SYMBOL

Broken at EVAL.  Type :H for Help.
    1  Return to top level. 
>>1

Top level.
>(setf (symbol-function 'deformed-symbol)
    NIL )

NIL

>(deformed-symbol)

Error: UNDEFINED-FUNCTION :NAME NIL
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by EVAL.
UNDEFINED-FUNCTION :NAME NIL

Broken at EVAL.  Type :H for Help.
    1  Return to top level. 
>>1

Top level.
>(setq 250 'deformed-symbol)

Error: TYPE-ERROR :DATUM 250 :EXPECTED-TYPE SYMBOL
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by SETQ.
TYPE-ERROR :DATUM 250 :EXPECTED-TYPE SYMBOL

Broken at SETQ.  Type :H for Help.
    1  Return to top level. 
>>1

Top level.
>(setq deformed-symbol 250)

250

>(defparameter *my-global*
    'deformed-symbol "Some Documentation")

*MY-GLOBAL*

>(eval '*my-global*)

DEFORMED-SYMBOL

>(eval *my-global*)

250

>(symbol-plist '*my-global*)

(SYSTEM:VARIABLE-DOCUMENTATION "Some Documentation")

>(symbol-plist *my-global*)

NIL

>deformed-symbol

250

>(deformed-symbol)

Error: UNDEFINED-FUNCTION :NAME NIL
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by EVAL.
UNDEFINED-FUNCTION :NAME NIL

Broken at EVAL.  Type :H for Help.
    1  Return to top level. 
>>1

Top level.
>(symbol-name 'deformed-symbol)

"DEFORMED-SYMBOL"

>


 

What I find most interesting in this example, is that when I did set the (symbol-function) of 'deformed-symbol to NIL, which is not a legal Function-definition, LISP mistook for this to be the new Name, which apparently it did back-reference to. The contrasting success of >(symbol-name 'deformed-symbol) may only have been due, to the scanning of the input lines, and perhaps to some added flexibility in the ability of the (symbol-name) function, when there is no more back-reference to the Name, still to find it.

(Edit 10/03/2016 : )

After much thought, I have come to conclude that this result, which is not meant to be repeated, when trying to write any sort of functioning ‘LISP-Program’, might have the following meaning:

Old code that still forms part of the LISP interpreter, may still scan the virtual CDR of a Symbol today, on the premise that it is a plist, to look for certain Keys, such as ‘:NAME‘. The reason this would not cause any conflicts with more-modern coding, is the fact that to scan a plist for Keywords, is harmless on ordinary Lists, until one of their top-level elements happens to equal the Key being looked for. This thinking would suggest, that when programmers use (symbol-plist), certain Key-Value combinations may be omitted in the result, so that (symbol-plist) does not really return the entire, internal plist.

But then it could be, that while the virtual CAR of a Value-Symbol holds its Value, the virtual CADR may hold any Function-definition, and the actual plist may then start from the virtual CDDR of the Symbol. This would not prevent old, internal code from just treating the CDR of the Symbol as the plist.

But, when I used (setf) to try to set a certain field to NIL, I may have invoked a slight bug in the way this works with (symbol-function), thus setting the entire CDR field of the Symbol to NIL. As soon as a scan of a plist fails to find a certain Key, it returns NIL, even if it was supposed to find the :NAME of a Symbol in the fastest way possible. And it will fail to find this Key, if the List is in fact NIL.

This might provide encouragement, when writing working code, always to use the #' syntax also, when using (setf (symbol-function 'some-symbol) #'(lambda ... )).

My assumption remains, that in order for Common LISP to distinguish between a Datum and a Symbol, the CDR field must be a CONS object – aka a List – to signal a Symbol. And NIL is also a special type of List. But anything else there, indicating a data-type, would suggest a Datum.

To add to my intrigue, the fact seems apparent that sometimes, the object (NIL.NIL) – aka '(NIL) – is also taken to be a Datum instead of a Symbol, perhaps due to not having any known Name. This would suggest that perhaps, a Datum needs to be identified as an Atom instead of as a List, just as a Symbol is:

 



GCL (GNU Common Lisp)  2.6.12 CLtL1    Oct 28 2014 10:02:30
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License:  GPL due to GPL'ed components: (XGCL READLINE UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/

>'(NIL)

(NIL)

>(NIL)

Error: UNDEFINED-FUNCTION :NAME NIL
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by EVAL.
UNDEFINED-FUNCTION :NAME NIL

Broken at EVAL.  Type :H for Help.
    1  Return to top level. 
>>1

Top level.
>(setf (symbol-function 'deformed-symbol)
    '(NIL) )

(NIL)

>(deformed-symbol)

Error: TYPE-ERROR :DATUM NIL :EXPECTED-TYPE CONS
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by EVAL.
TYPE-ERROR :DATUM NIL :EXPECTED-TYPE CONS

Broken at :ZOMBI.  Type :H for Help.
    1  Return to top level. 
>>1

Top level.
>(quit)


 

Dirk

 

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *

Please Prove You Are Not A Robot *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>