screwlisp proposes kittens

Line plotting Alexandria’s forms’ atom heights (!) (Just look.)

Look at the one at the end.

In the article I just wrote musing about headings, I was gnuplot line plotting lisp forms. Here I am doing one for Common Lisp’s Alexandria. Alexandria is a special package which it is assumed you have always loaded for the most part. For example, the ANSI CL standard doesn’t include flatten or association-list-to-hash-table, but Alexandria does.

Let’s do one with every form from "~/common-lisp/alexandria/alexandria-1/hash-tables.lisp". Er, I’m going to use cl-series.

defun a call to gnuplot

From here again. It’s going to need to be modified to be noninteractive, but interactive is fine for now.

(defun gnuplot (title &rest x-y-lists)
  (let ((cmd (format
	      nil
	      "gnuplot -p -e "~
set title '~a'; ~
unset key; ~
unset xtics; ~
set xrange [~,1f:~,1f]; ~
set yrange [~,1f:~,1f]; ~
plot ~{~1*'-' using 1:2 with lines~^,~^ ~};~
""
	      title
	      (apply 'min (mapcar 'car (apply 'append x-y-lists)))
	      (apply 'max (mapcar 'car (apply 'append x-y-lists)))
	      (apply 'min (mapcar 'cadr (apply 'append x-y-lists)))
	      (apply 'max (mapcar 'cadr (apply 'append x-y-lists)))
	      x-y-lists)))
    (with-input-from-string
	(in (format nil "~{~{~{~,1f ~,1f~}~%~}e~^~%~}" x-y-lists))
      (uiop:run-program cmd :input in))))

Turn a lisp form into a atom-depth list

From here, a moment ago

(defun atom-heights (form &optional (height 0))
  (loop
    :for item :in form
    :if (atom item) :collect
      height :into heights
    :else
      :nconc (atom-heights item (1+ height)) :into heights
    :if (atom item) :collect
      item :into items
    :else
      :nconc (nth-value 1 (atom-heights item)) :into items
    :finally
       (return (values heights items))))

Install cl-series

 (setq eepitch-buffer-name "*slime-repl ECL*")
(require :series)
(series::install)

Get all the lisp files in a directory

name wild type lisp wild inferiors current directory

(let* ((current-dir (car (directory #p"./")))
       (wild-dir
	 (make-pathname :directory
			'(:relative :wild-inferiors))
	 )
       (wild-here
	 (merge-pathnames  wild-dir current-dir))
       (lisp-files
	 (make-pathname :name :wild :type "lisp"))
       (lisp-here (merge-pathnames wild-here lisp-files)))
  lisp-here)

Get those.

(directory *)

Graph one of those.

(second *)
(scan-file *)
(collect *)
(third *)
(nth-value 0 (atom-heights *))

Plot that like before.

(let* ((ys (mapcar 'list *))
	 (xs (loop :for x from 0 :below (length ys)
		   :collect x)))
    (gnuplot "sequence-of-length-p from alexandria"
	     (pairlis xs ys)))

Neat. This implies

Plot the whole file, hoping not to run out of heap

(defun plot-file-heights (file)
  (let* ((z (scan-file file))
	 (exprs (collect z)))
    (apply
     'gnuplot
     (pathname-name file)
     (loop :for expr :in exprs
	   :for heights := (atom-heights expr)
	   :for ys := (mapcar 'list heights)
	   :for xs := (loop :for x :below (length ys)
			    :collect x)
	   :collect (mapcar 'cons xs ys)))))

#p"alexandria-1/sequences.lisp"

(plot-file-heights
 #P"~/common-lisp/alexandria/alexandria-1/sequences.lisp")

Conclusions

I have to say, that was deeply satisfying.

Fin.

  1. Show me you doing ⬆ or seek help
  2. Discuss what information is visible ??

on the Mastodon thread.

Bonus

#p"marklib.lisp" from Arrokoth

screwlisp proposes kittens