#| I dunno, I like writing this quine: |# ;;; Loading #P"ecl/asdf.fas" ;;; Loading "15sph.fas" ; (princ (nth-value 1 (ignore-errors (let ((amble '((QUINE LAMBDA (X) (DEFVAR *DATA* (CDR (ASSOC 'DATA X))) (DEFVAR *SIDE-EFFECTS* (CDR (ASSOC 'SIDE-EFFECTS X))) "Special scope *data* *side-effects* alists" (MAPC 'FUNCALL (MAPCAR 'EVAL *SIDE-EFFECTS*)) (SETF (CDR (ASSOC 'DATA X)) *DATA*) (SETF (CDR (ASSOC 'SIDE-EFFECTS X)) *SIDE-EFFECTS*) (FORMAT T "(princ (nth-value 1 (ignore-errors (let ((amble '~s)) (funcall (eval (cdr (assoc 'quine amble))) amble) (terpri) (princ '|;;error :|) )))) (si:quit)" X)) (DATA . FOO) (SIDE-EFFECTS (LAMBDA () (FORMAT T ";~%")))))) (funcall (eval (cdr (assoc 'quine amble))) amble) (terpri) (princ '|;;error :|) )))) (si:quit) ;;error :NIL #| The quine loads, does something possibly modifying itself, and prints itself to *standard-output*, appending an error comment of either nil or an error if ignore-errors experienced one before quitting. Because defvar won't overwrite a bound variable, *data* and *side-effects* can be clobbered at the top of the file. Otherwise those are preserved in the lexical closure such that it is. This filesystem closure lends itself to an odd behavior. ecl -load quine1.lisp > quine2.lisp ecl -load quine2.lisp > quine3.lisp ecl -load quine3.lisp > quine4.lisp ecl <<EOG (compile-file #p"quine4.lisp") EOG ecl -load quine4.fas > quine5.lisp I guess the outputting could be done in lisp rather than ksh. Other than being annoying, it creates a natural history that can be rejoined and overridden where-ever. The customisation kind of sucks, having to declare all the state in special scope up front, including a single, flat list of argless functions that will happen in order, presumably working on the *data* alist. Because of the ridiculousness, I didn't finish the code I was working on this weekend- using that png-pixels.lisp I wrote an age ago to slowly asciifi an image. Actually I want to tack on another absurdity: In general loading :usocket and having the started closure files interactable over gopher protocol. Then every time state is modified, a new pseudoclosure is created and its gopher started (on a different port). In this way at least, it creates a many-reads one-write scenario (while rapidly running out of ports). I did this after listening to an octogenarian Alan Kay condemn fiddling individual programs towards perfection when large, multi-scale systems of cheap, modular servers are where he sees the future with an emphasis on no-fail systems. This reminded me of igorstw who started appearing recently, saying that the state of machine learning at the moment is a verdant ground where individual insight and creativity dominate compared to lumbering corporate wealth, in an interesting rejection of chatgpt popular infamy. I think after I have a large and self-sustaining population of robot gophers, I will have them syncronise in some sense over a mock-activitypub. Since it's not important to me personally to use http request types nor json for data, nor https on a local subnet, I will just relax that out of an otherwise similar implementation (it can be tacked on later at little cost). Except that I don't know telnet at all, it would be cool if I could grab control of individual robot gophers using the telnet itemtype. (REPL access remains important to Kay). |#