screwlisp proposes kittens

A very short note on common lisp’s sharpsign equal-sign including circular list definitions that should probably be understood as a joke.

I was quickly reviewing this while mulling over Kay’s idea that

Every object should have its own URL

after https://mdhughes.tech suggested that every map entity in some map editors (viz my NicCLIM) could have its own unique properties.

I considered the lisp:classic idea that every unique (in the sense of eq) symbol has its own plist. I guess I would stipulate these with lisp’s sharpsign equals sign reader macro function, which provides a headless reference when writing such things.

We often see this in creating circular loops, but it is a more general facility.

An uninterned symbol with a plist one-liner

CL-USER> (prog1 '#1=#:foo (setf (symbol-plist '#1#) '(:foo #2=#:foo #2# foo foo #2#)))
#:FOO
CL-USER> (symbol-plist *)
(:FOO #1=#:FOO #1# FOO FOO #1#)
CL-USER> (getf * (getf * (getf * :foo)))
#:FOO

The prog1 form

Call #:foo (a new uninterned symbol of symbol-name "FOO") #1#. setf the plist of #1#, i.e. the previous #1= thing.

The plist pairs

  1. The (intern "FOO" :keyword) keyword with a new uninterned symbol, symbol-name "FOO"— call it #2#.
  2. #2# from 1. keys an interned symbol of the current package, i.e. (intern "FOO").
  3. The interned symbol FOO keys the uninterned symbol here called #2# again.

Tree sharpsign equals example

Imagine ~/tree.lisp:

(defparameter *trees*
  (prog1
      '(#1=#:tree #2=#:tree)

    (setf (get '#1# :inhabitants) '(owl)
	  (get '#2# :inhabitants) '(#3=#:monkey #3# #:monkey))))

Let’s investigate whom is eq to whom.

CL-USER> (load #P"~/tree.lisp")
#P"/home/screwlisp/tree.lisp"
CL-USER> *trees*
(#:TREE #:TREE)
CL-USER> (eq (car *) (cadr *))
NIL
CL-USER> (get (car **) :inhabitants)
(OWL)
CL-USER> (get (car ***) :inhabitants)
(OWL)
CL-USER> *trees*
(#:TREE #:TREE)
CL-USER> (eq (car *) (cadr *))
NIL
CL-USER> (get (car **) :inhabitants)
(OWL)
CL-USER> (get (cadr ***) :inhabitants)
(#1=#:MONKEY #1# #:MONKEY)
CL-USER> (eq (car *) (cadr *))
T
CL-USER> (eq (car **) (caddr **))
NIL

Circular lists

Oh, right, these too.

CL-USER> (setq *print-circle* t)
T
CL-USER> '#1=(1 (2 #1#) 3 #1#)
#1=(1 (2 #1#) 3 #1#)
CL-USER> (eq * (cadadr *))
T
CL-USER> (eq (cadadr **) (cadddr **))
T

Don’t forget *print-circle* it checks to make sure it is not ever trying to print a circle which has a cost, but it does allow the printing of circles.

Conclusions

I can’t possibly imagine this helped someone, but I hope you are familiar with the sharpsign equal sign now.

Fin.

Share your pathos on the Mastodon.

screwlisp proposes kittens