lisp

1. Apply-Eval

Maxwell's equations of Software (Alan Kay in some Interview)

(define (apply fn x a)
    (cond
      ((atom fn)
       (cond
         ((eq fn CAR)  (caar x))
         ((eq fn CDR)  (cdar x))
         ((eq fn CONS) (cons (car x) (cadr x)))
         ((eq fn ATOM) (atom (car x)))
         ((eq fn EQ)   (eq (car x) (cadr x)))
         (#t           (apply (eval fn a) x a))))
      ((eq (car fn) LAMBDA)
       (eval (caddr fn) (pairlis (cadr fn) x a)))
      ((eq (car fn) LABEL)
       (apply (caddr fn) x
              (cons (cons (cadr fn) (caddr fn)) a)))))

(define (eval e a)
    (cond
      ((atom e) (cdr (assoc e a)))
      ((atom (car e))
       (cond ((eq (car e) QUOTE) (cadr e))
             ((eq (car e) COND)  (evcon (cdr e) a))
             (#t                 (apply (car e) (evlis (cdr e) a) a))))
      (#t       (apply (car e) (evlis (cdr e) a) a))))

2. Comment Stream

2.1. 0x2211

  • getting into "On Lisp" Now

2.2. 0x21F4

  • Researching deeper into lisp being a universal representation of compute.
    • the core boils down to abstract syntax trees being an intermediate for any compiled/interpreted languages
    • what the computer finally understands is assembly but when it comes to representing programs - nothing beats the symbolic completeness of lisp

2.3. 0x21BF

  • rotatef acts as a generalized swapper
(let ((a 'x)
      (b 'y)
      (c 'z))
  (rotatef a b c)
  `(,a ,b ,c))
Y Z X
  • "multiple-value-bind" helps catch multiple returns from a form and execute a body under these binds
  • to return multiple values use the "values" function
  • reading about utiliTies and noticed proclaiming inlines being a common idiom when working with them
(proclaim '(inline <relatively smaller utilities>))

2.4. 0x21BE

  • all those accumulation to force tail recursions need to surely be optimized
  • mix these in with type declarations, and one might surpass the speed of c.
(proclaim '(optimize speed))
  • lambda expressions are a fancy way (I still prefer them) of saying "literal functions"

2.5. 0x21B7

  • finishing off practical common lisp

2.6. 0x2150

  • updated keyworded args for lisp lambda lists
    • based on the above knowledge, creating a general selector to for a list of records ( a db )
    • this is to be used in conjunction with a filter (remove-if-not in cl)
(defvar *db* '()) ;populate *db* with records
(defvar *fields* '(title artist rating ripped)) 

(defun where (&key (title nil title-p)
                (artist nil artist-p)
                (rating nil rating-p)
                (ripped nil ripped-p))
  #'(lambda (record)
      (and (if title-p (equal (getf cd :title)
                              title))
           (if artist-p (equal (getf cd :artist)
                               artist))
           (if rating-p (equal (getf cd :rating)
                               rating))
           (if ripped-p (equal (getf cd :ripped)
                               ripped)))))
  • note that we don't need a passage predicate for variables when you're not dealing with booleans (title, artist and rating in this case)
    • staying pedagogical anyway though.
  • this similarly could be extended to updating particular records based on a selector function as above
  • the author's talking a little about macros now …
  • done with C3, entering a more formal phase of the book
  • few naming conventions
    • surround global vars in *
    • surround constant vars in +
    • start low level functions with %
      • %% for even lower level functions
  • recalling again that special operators can't be emulated via functions or macros ("if" for instance)

2.7. 0x214F

  • exploring format directives
    • (format <stream> <format string with directives> <symbols>)
directive functionality
~a aesthetics(render without quotes and leading :)
~r print out numbers in english
~t tabulating (~10t for 10 column spaces for instance)
~{ ~} consume symbols from a list
~% force a new line
~& conditional new line : only if not on a newline already

  • saving and loading files follows a generic common structure
(defun save-file (filename)
  (with-open-file (out filename
                       :direction :output
                       :if-exists :supersede)
    (with-standard-io-syntax
      (print object-to-be-dumped out))))

(defun load-file (filename)
  (with-open-file (in filename) ;defaults tuned for input
    (with-standard-io-syntax
      (setf object-to-be-read-into (read in)))))

  • another reminder of common lisp using #'remove-if-not rather than #'filter
  • equal compares everything element by element…

  • the author calls for a quick refresher of keyword parameters -> see lisp lambda lists

2.8. 0x2142

  • just noticed that streams are inefficient when reading chapters across days.
  • using scratch for continuous evaluations and will dump the corresponding code at once whenever I'm done with a particular section
  • that way, I won't need to address similar notions twice over multiple days
  • the objective isn't to build good notes but be practical…
  • alright, just flew off a tangent and spent some time on symbol <-> interop to generate code in a parametric manner
  • still a little too rough around the edges -> I bet I might be conceptually messing it up somewhere and a better way exists.., but I got a generic function definer working that can generate getters from a list…
  • cool xp, dumping the code below..:
(defvar *db* nil)
(defvar *indicator-list* (list 'title 'artist 'rating 'ripped))

(defun make-record (title artist rating ripped)
  (list :title title
        :artist artist
        :rating rating
        :ripped ripped))

(defvar test-record (make-record "sentinel title"
                                 "sentinel artist"
                                 "sentinel rating"
                                 "sentinel ripped"))
(defun add-record (cd)
  (push cd *db*))

(defun generate-getters (indicator-list)
  (defun build-key (symbol)
    (read-from-string (concatenate 'string
                                   ":"
                                   (string symbol))))
  (eval
   (let ((defuns (mapcar
                  #'(lambda (indicator)
                      (let ((func-name
                              (read-from-string
                               (concatenate 'string
                                            "get-"
                                            (string indicator)))))
                        `(defun ,func-name (record-plist)
                           (getf record-plist ,(build-key indicator)))))
                  indicator-list)))
     `(progn ,@defuns))))

(generate-getters *indicator-list*)
  • do note that ,@ is a list splicer that elevates all the elements in a list to be elements in the parent where it is invoked (in a backquoted list)

2.9. 0x213F

  • starting C3 : a simple database
  • plists : dictionaries built upon lists (the worst hash table possible)
    • every even element is a symbol (a key)

`(,(setf plis (list :a 1 :b 2 :c 3))
   ,(getf plis :a)
   ,(getf plis :b))
(:A 1 :B 2 :C 3) 1 2

  • note that there are no separate constructors for a plist : it's just a list with different contents
  • getf to access the values associated with a key
  • is a way to store a record for our db

(defun make-cd (title artist rating ripped)
  (list :title title
        :artist artist
        :rating rating
        :ripped ripped))

(make-cd 'Stayin-alive 'Bees-Gees '? NIL)

  • the global var db can hold all the cds
  • do note that this is a special variable with dynamic scoping that the author does not refer to in this case.
(defvar *db* nil)
(let ((cd (make-cd .. .. .. ..))))

2.10. 0x213C

  • started my first formal pass of Practical Common Lisp
  • done with Common Lisp: A gentle introduction to symbolic computation
  • will be actively noting down in this pass : did not with the latter - only solved involved excercises and was a quick skim.
  • Peter touts a flowy language design for lisp due to its dynamic typing and condition system to handle errors : I'm yet to explore the latter..
  • paradigmatic changes can be absorbed without altering the base language.
  • btw, let's get over with something very important before we proceed.


    'Hello-world
    
    HELLO-WORLD
    

  • alright, lets go..
  • C2 : a tour of the repl
  • a debugger right out of the box is nice
    • no core dumps / stack traces
  • loading source into the lisp process involves two basic steps :

    1. compile the source into a .fasl
    2. load the .fasl into the process
    • during interactive development, compile-defun should suffice
    • for a complete file, compile-and-load should be accessible in whatever environment you choose to use


  • do notice the structure of a fasl for the following program:
(defun hello-world ()
  (format t "~&~S" 'hello-world))
  • it seems to be mixture of byte code and the interpretable literals that make up the program.
  • some explicit inbuilts like declare, block, format can also be observed.
  • note that a .fasl in itself isn't an executable and needs an implementation (sbcl in this case) to go along with it -> (literally speaking, it is a "FASt Loadable")

2.11. 0x2132

starting a new youtube common lisp series:-

2.12. 0x212C

  • gensyms are internal temp variables that are guaranteed to have no name resolution conflicts -> one can't input them via a keyboard/conventional methods
  • init with defvar, defparameter, defconstant -> dynamically scoped
  • init with setf -> lexically scoped

2.13. 0x212B

2.14. 0x211D

2.15. 0x2118

AKA List Processing

My first proper introduction to lisp was via SICP and I've been smitten since. I've felt the most natural programming in lisp. Even though I completed the exercises of SICP with a scheme (racket), I've chosen to proceed with common lisp for the long term.

Emacs has been something that I once spent 4 days on, migrating my workflows from vim. It is an operating system in itself and I spend most of my personal time in emacs.

I'm still a novice and haven't built anything of consequence in lisp: I wish to change that soon and am actively looking for a modern project idea in lisp - could be building an emacs extension or writing something that stands alone.

3. Literature Queue

  • Structure and Interpretation of Computer Programs
  • Common Lisp: An introduction to symbolic computation -> book review
  • Practical Common Lisp
  • [ … ] On Lisp
  • [ ] Let over Lambda
  • [ ] The Art of the MetaObject Protocol
  • [ ] Professional Automated Trading : Theory and Practice

4. Sentinel refs

4.1. Structure and Interpretation of Computer Programs

4.2. Common Lisp: A gentle introduction to symbolic computation

4.3. Practical Common Lisp

  • Beginning formal pass of practical common lisp 0x213C.
  • now that org-babel is setup, the comment stream should be more lively

4.4. The Common Lisp Cookbook

Tags::lisp: