<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title> Lisp journey</title>
    <link>/</link>
    <description>Recent content on Lisp journey</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 11 Feb 2026 23:35:40 +0100</lastBuildDate>
    
        <atom:link href="/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>🖌️ Lisp screenshots: today&#39;s Common Lisp applications in action</title>
      <link>/blog/lisp-screenshots-todays-common-lisp-applications-in-action/</link>
      <pubDate>Wed, 11 Feb 2026 23:35:40 +0100</pubDate>
      
      <guid>/blog/lisp-screenshots-todays-common-lisp-applications-in-action/</guid>
      <description>&lt;p&gt;I released a hopefully inspiring gallery:&lt;/p&gt;



&lt;p&gt;
  &lt;h2 align=&#34;center&#34;&gt;  &lt;a align=&#34;center&#34; href=&#34;http://www.lisp-screenshots.org/&#34;&gt;lisp-screenshots.org&lt;/a&gt; &lt;/h2&gt;
  &lt;!-- &lt;h3 align=&#34;center&#34;&gt; Today&#39;s Common Lisp applications in action. &lt;/h3&gt; --&gt;
  &lt;a href=&#34;http://www.lisp-screenshots.org/&#34;&gt;
    &lt;img style=&#34;max-width: 100%&#34; src=&#34;/lisp-screenshots.png&#34;&gt;&lt;/img&gt;
  &lt;/a&gt;
&lt;/p&gt;



&lt;p&gt;We divide the showcase under the categories &lt;strong&gt;Music&lt;/strong&gt;, &lt;strong&gt;Games&lt;/strong&gt;, &lt;strong&gt;Graphics and CAD&lt;/strong&gt;, &lt;strong&gt;Science and industry&lt;/strong&gt;, &lt;strong&gt;Web applications&lt;/strong&gt;, &lt;strong&gt;Editors&lt;/strong&gt; and &lt;strong&gt;Utilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Of course:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Please don&amp;rsquo;t assume Lisp is only useful for…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;thank you ;)&lt;/p&gt;

&lt;p&gt;For more example of companies using CL in production, see &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;this list&lt;/a&gt; (contributions welcome, of course).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Don&amp;rsquo;t hesitate to share a screenshot of your app! It can be closed
source and yourself as the sole user, as long as it as some sort of a
GUI, and you use it. Historical success stories are for
another collection.&lt;/p&gt;

&lt;p&gt;The criteria are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;built in Common Lisp&lt;/li&gt;
&lt;li&gt;with some sort of a graphical interface&lt;/li&gt;
&lt;li&gt;targeted at end users&lt;/li&gt;
&lt;li&gt;a clear reference, anywhere on the web, by email to me or simply as a comment here, that it is built in CL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it can be web applications whose server side is CL, even if the JS/HTML is classical web tech.&lt;/li&gt;
&lt;li&gt;no CLI interfaces. A readline app is OK but hey, we can do better.&lt;/li&gt;
&lt;li&gt;it can be closed-source or open-source, commercial, research or a personal software&lt;/li&gt;
&lt;li&gt;regarding &amp;ldquo;end users&amp;rdquo;: I don&amp;rsquo;t see how to include a tool like CEPL, but I did include a screen of LispWorks.&lt;/li&gt;
&lt;li&gt;bonus point if it is developed in a company (we want it on &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;https://github.com/azzamsa/awesome-lisp-companies/&lt;/a&gt;), be it a commercial product or an internal tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can reach us on &lt;a href=&#34;https://github.com/vindarel/lisp-screenshots/discussions/&#34;&gt;GitHub discussions&lt;/a&gt;, by email at &lt;code&gt;(reverse &amp;quot;gro.zliam@stohsneercs+leradniv&amp;quot;)&lt;/code&gt; and in the comments.&lt;/p&gt;

&lt;p&gt;Best,&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Practice for Advent Of Code in Common Lisp</title>
      <link>/blog/practice-for-advent-of-code-in-common-lisp/</link>
      <pubDate>Sun, 30 Nov 2025 19:12:07 +0100</pubDate>
      
      <guid>/blog/practice-for-advent-of-code-in-common-lisp/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent Of Code 2025&lt;/a&gt; starts in a few
hours. Time to practice your Lisp-fu to solve it with the greatest
language of all times this year!&lt;/p&gt;

&lt;p&gt;Most of the times, puzzles start with a string input we have to parse
to a meaningful data structure, after which we can start working on
the algorithm. For example, parse this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *input* &amp;quot;3   4
4   3
2   5
1   3
3   9
3   3&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;into a list of list of integers, or this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *input* &amp;quot;....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;into a grid, a map. But how do you represent it, how to do it
efficiently, what are the traps to avoid, are there some nice tricks
to know? We&amp;rsquo;ll try together.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll find those 3 exercises of increasing order also in the &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/tree/master/exercises/chapter%20-%20data%20structures&#34;&gt;GitHub
repository&lt;/a&gt;
of my course (see my &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/learn-lisp-data-structures-9-videos-90-minutes/&#34;&gt;previous post on the new data structures
chapter&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I give you fully-annotated puzzles and code layout. You&amp;rsquo;ll have to
carefully read the instructions, think about how you would solve it
yourself, read my proposals, and fill-in the blanks -or do it all by
yourself. Then, you&amp;rsquo;ll have to check your solution with your own
puzzle input you have to grab from AOC&amp;rsquo;s website!&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#prerequisites&#34;&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#exercise-1---lists-of-lists&#34;&gt;Exercise 1 - lists of lists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#exercise-2---prepare-to-parse-a-grid-as-a-hash-table&#34;&gt;Exercise 2 - prepare to parse a grid as a hash-table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#harder-puzzle---hash-tables-grid-coordinates&#34;&gt;Harder puzzle - hash-tables, grid, coordinates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-words&#34;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;You must know the basics, but not so much. And if you are an
experienced Lisp developer, you can still find new constraints for
this year: solve it with &lt;code&gt;loop&lt;/code&gt;, without &lt;code&gt;loop&lt;/code&gt;, with a
purely-functional data structure library such as FSet, use Coalton, create
animations, use the object system, etc.&lt;/p&gt;

&lt;p&gt;If you are starting out, you must know at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the basic data structures (lists and their limitations, arrays and vectors, hash-tables, sets…)&lt;/li&gt;
&lt;li&gt;iteration (iterating over a list, arrays and hash-table keys)&lt;/li&gt;
&lt;li&gt;functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;no need of macros, CLOS or thorough error handling (it&amp;rsquo;s not about production-grade puzzles :p ).&lt;/p&gt;

&lt;h2 id=&#34;exercise-1-lists-of-lists&#34;&gt;Exercise 1 - lists of lists&lt;/h2&gt;

&lt;p&gt;This exercise comes from Advent Of Code 2024, day 01: &lt;a href=&#34;https://adventofcode.com/2024/day/1&#34;&gt;https://adventofcode.com/2024/day/1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read the puzzle there! Try with your own input data!&lt;/p&gt;

&lt;p&gt;Here are the shortened instructions.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;;
;;; ********************************************************************
;;; WARN: this exercise migth be hard if you don&#39;t know about functions.
;;; ********************************************************************
;;;
;;; you can come back to it later.
;;; But, you can have a look, explore and get something out of it.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this exercise, we use:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;; SORT
;;; ABS
;;; FIRST, SECOND
;;; EQUAL
;;; LOOP, MAPCAR, REDUCE to iterate and act on lists.
;;; REMOVE-IF
;;; PARSE-INTEGER
;;; UIOP (built-in) and a couple string-related functions
;;;
;;; and also:
;;; feature flags
;;; ERROR
;;;
;;; we don&#39;t rely on https://github.com/vindarel/cl-str/
;;; (nor on cl-ppcre https://common-lisp-libraries.readthedocs.io/cl-ppcre/)
;;; but it would make our life easier.
;;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, so this is your puzzle input, a string representing two colums of integers.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *input* &amp;quot;3   4
4   3
2   5
1   3
3   9
3   3&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We&amp;rsquo;ll need to parse this string into two lists of integers.&lt;/p&gt;

&lt;p&gt;If you want to do it yourself, take the time you need! If you&amp;rsquo;re new to Lisp iteration and data structures, I give you a possible solution.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;; [hiding in case you want to do it…]
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;
;;;

(defun split-lines (s)
  &amp;quot;Split the string S by newlines.
  Return: a list of strings.&amp;quot;
  ;; If you already quickloaded the STR library, see:
  ;; (str:lines s)
  ;;
  ;; UIOP comes with ASDF which comes with your implementation.
  ;; https://asdf.common-lisp.dev/uiop.html
  ;;
  ;; #\ is a built-in reader-macro to write a character by name.
  (uiop:split-string s :separator &#39;(#\Newline)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Compile the function and try it on the REPL, or with a quick test expression below a &amp;ldquo;feature flag&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;We get a result like &lt;code&gt;&#39;(&amp;quot;3   4&amp;quot; &amp;quot;4   3&amp;quot; &amp;quot;2   5&amp;quot; &amp;quot;1   3&amp;quot; &amp;quot;3   9&amp;quot; &amp;quot;3   3&amp;quot;)&lt;/code&gt;, that is a list of strings with numbers inside.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+lets-try-it-out
;; This is a feature-flag that looks into this keyword in the top-level *features* list.
;; The expression below should be highlihgted in grey
;; because :lets-try-it-out doesn&#39;t exist in your *features* list.
;;
;; You can compile this with C-c C-c
;; Nothing should happen.
(assert (equal &#39;(&amp;quot;3   4&amp;quot; &amp;quot;4   3&amp;quot; &amp;quot;2   5&amp;quot; &amp;quot;1   3&amp;quot; &amp;quot;3   9&amp;quot; &amp;quot;3   3&amp;quot;)
               (split-lines *input*)))
;;                                   ^^ you can put the cursor here and eval the expression with C-x C-e, or send it to the REPL with C-c C-j.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We now have to extract the integers inside each string.&lt;/p&gt;

&lt;p&gt;To do this I&amp;rsquo;ll use a utility function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; We could inline it.
;; But, measure before trying any speed improvement.
(defun blank-string-p (s)
  &amp;quot;S is a blank string (no content).&amp;quot;
  ;; the -p is for &amp;quot;predicate&amp;quot; (returns nil or t (or a truthy value)), it&#39;s a convention.
  ;;
  ;; We already have str:blankp in STR,
  ;; and we wouldn&#39;t need this function if we used str:words.
  (equal &amp;quot;&amp;quot; s))  ;; better: pair with string-trim.

#+(or)
(blank-string-p nil)
#++
(blank-string-p 42)
#+(or)
(blank-string-p &amp;quot;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And another one, to split by spaces:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun split-words (s)
  &amp;quot;Split the string S by spaces and only return non-blank results.

  Example:

    (split-words \&amp;quot;3    4\&amp;quot;)
    =&amp;gt; (\&amp;quot;3\&amp;quot; \&amp;quot;4\&amp;quot;)
  &amp;quot;
  ;; If you quickloaded the STR library, see:
  ;; (str:words s)
  ;; which actually uses cl-ppcre under the hood to split by the \\s+ regexp,
  ;; and ignore consecutive whitespaces like this.
  ;;
  (let ((strings (uiop:split-string s :separator &#39;(#\Space))))
    (remove-if #&#39;blank-string-p strings)))

#+lets-try-it-out
;; test this however you like.
(split-words &amp;quot;3       4&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I said we wouldn&amp;rsquo;t use a third-party library for this first puzzle. But using &lt;code&gt;cl-ppcre&lt;/code&gt; would be so much easier:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ppcre:all-matches-as-strings &amp;quot;\\d+&amp;quot; &amp;quot;3  6&amp;quot;)
;; =&amp;gt; (&amp;quot;3&amp;quot; &amp;quot;6&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With our building blocks, this is how I would parse our input string
into a list of list of integers.&lt;/p&gt;

&lt;p&gt;We &lt;code&gt;loop&lt;/code&gt; on input lines and use the built-in function &lt;code&gt;parse-integer&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun parse-input (input)
  &amp;quot;Parse the multi-line INPUT into a list of two lists of integers.&amp;quot;
  ;; loop! I like loop.
  ;; We see everything about loop in the iteration chapter.
  ;;
  ;; Here, we see one way to iterate over lists:
  ;; loop for … in …
  ;;
  ;; Oh, you can rewrite it in a more functional style if you want.
  (loop :for line :in (split-lines input)
        :for words := (split-words line)
        :collect (parse-integer (first words)) :into col1
        :collect (parse-integer (second words)) :into col2
        :finally (return (list col1 col2))))

#+lets-try-it-out
(parse-input *input*)
;; ((3 4 2 1 3 3) (4 3 5 3 9 3))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;The puzzle continues&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Maybe the lists are only off by a small amount! To find
out, pair up the numbers and measure how far apart they are. Pair
up the smallest number in the left list with the smallest number
in the right list, then the second-smallest left number with the
second-smallest right number, and so on.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;=&amp;gt; we need to SORT the columns by ascending order.;;;&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Within each pair, figure out how far apart the two numbers are;&amp;rdquo;&lt;/p&gt;

&lt;p&gt;=&amp;gt; we need to compute their relative, absolute distance.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;you&amp;rsquo;ll need to add up all of those distances.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;=&amp;gt; we need to sum each relative distance.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;For example, if you pair up a 3 from the left list with a 7 from
the right list, the distance apart is 4; if you pair up a 9 with a
3, the distance apart is 6.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Our input data&amp;rsquo;s sum of the distances is 11.&lt;/p&gt;

&lt;p&gt;We must sort our lists of numbers. Here&amp;rsquo;s a &lt;em&gt;placeholder&lt;/em&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun sort-columns (list-of-lists)
  &amp;quot;Accept a list of two lists.
  Sort each list in ascending order.
  Return a list of two lists, each sorted.&amp;quot;
  ;; no mystery, use the SORT function.
  (error &amp;quot;not implemented&amp;quot;))

;; Use this to check your SORT-COLUMNS function.
;; You can write this in a proper test function if you want.
#+lets-try-it-out
(assert (equal (sort-columns (parse-input *input*))
               &#39;((1 2 3 3 3 4) (3 3 3 4 5 9))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Compute the absolute distance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; utility function.
(defun distance (a b)
  &amp;quot;The distance between a and b.
  Doesn&#39;t matter if a &amp;lt; b or b &amp;lt; a.&amp;quot;
  ;;
  ;; hint: (abs -1) is 1
  ;;
  (error &amp;quot;not implemented&amp;quot;)
  )

(defun distances (list-of-lists)
  &amp;quot;From a list of two lists, compute the absolute distance between each point.
  Return a list of integers.&amp;quot;
  (error &amp;quot;not implemented&amp;quot;)
  ;; hint:
  ;; (mapcar #&#39;TODO (first list-of-lists) (second list-of-lists))
  ;;
  ;; mapcar is a functional-y way to iterate over lists.
  )


(defun sum-distances (list-of-integers)
  &amp;quot;Add the numbers in this list together.&amp;quot;
  (error &amp;quot;not implemented&amp;quot;)
  ;; Hint:
  ;; try apply, funcall, mapcar, reduce.
  ;; (TODO #&#39;+ list-of-integers)
  ;; or loop … sum !
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Verify.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun solve (&amp;amp;optional (input *input*))
  ;; let it flow:
  (sum-distances (distances (sort-columns (parse-input input)))))

#+lets-try-it-out
(assert (equal 11 (solve)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All good? There&amp;rsquo;s more if you want.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;;
;;; Next:
;;; - do it with your own input data!
;;; - do the same with the STR library and/or CL-PPCRE.
;;; - write a top-level instructions that calls our &amp;quot;main&amp;quot; function so that you can call this file as a script from the command line, with sbcl --load AOC-2024-day01.lisp
;;;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;exercise-2-prepare-to-parse-a-grid-as-a-hash-table&#34;&gt;Exercise 2 - prepare to parse a grid as a hash-table&lt;/h2&gt;

&lt;p&gt;This exercise is a short and easy, to prepare you for a harder puzzle. This is not an AOC puzzle itself.&lt;/p&gt;

&lt;p&gt;Follow the instructions. We are only warming up.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Do this with only CL built-ins,
;; or with the dict notation from Serapeum,
;; or with something else,
;; or all three one after the other.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We will build up a grid stored in a hash-table to represent a map like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;....#...##....#&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where the &lt;code&gt;#&lt;/code&gt; character represents an obstacle.&lt;/p&gt;

&lt;p&gt;In our case the grid is in 1D, it is often rather 2D.&lt;/p&gt;

&lt;p&gt;This grid/map is the base of many AOC puzzles.&lt;/p&gt;

&lt;p&gt;Take a second: shall we represent a 2D grid as a list of lists, or something else,
(it depends on the input size)
and how would you do in both cases?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Your turn&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;
;; 1. Define a function MAKE-GRID that returns an empty grid (hash-table).
;;
(defun make-grid ()
  ;; todo
  )


;;
;; Define a top-level parameter to represent a grid that defaults to an empty grid.
;;

;; def… *grid* …

;;
;; 2. Create a function named CELL that returns a hash-table with those keys:
;; :char -&amp;gt; holds the character of the grid at this coordinate.
;; :visited or :visited-p or even :visited? -&amp;gt; stores a boolean,
;;  to tell us if this cell was already visited (by a person walking in the map). It defaults
;;  to NIL, we don&#39;t use this yet.
;;

(defun cell (char &amp;amp;key visited)
  ;; todo
  )

;;
;; 3. Write a function to tell us if a cell is an obstacle,
;;    denoted by the #\# character
;;
(defun is-block (cell)
  &amp;quot;This cell is a block, an obstacle. Return: boolean.&amp;quot;
  ;; todo
  ;; get the :char key,
  ;; check it equals the #\# char.
  ;; Accept a cell as NIL.
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We built utility functions we&amp;rsquo;ll likely re-use on a more complex puzzle.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s continue with parsing the input to represent a grid.&lt;/p&gt;

&lt;p&gt;If you are a Lisp beginner or only saw the data structures chapter in
my course, I give you the layout of the &lt;code&gt;parse-input&lt;/code&gt; function with a
&lt;code&gt;loop&lt;/code&gt; and you only have to fill-in one blank.&lt;/p&gt;

&lt;p&gt;In any case, try yourself. Refer to the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/iteration.html&#34;&gt;Cookbook&lt;/a&gt; for &lt;code&gt;loop&lt;/code&gt;
examples.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;
;; 4. Fill the grid (with devel data).
;;
;; Iterate on a given string (the puzzle input),
;; create the grid,
;; keep track of the X coordinate,
;; for each character in the input create a cell,
;; associate the coordinate to this cell in the grid.
;;

(defparameter *input* &amp;quot;.....#..#.##...#........##...&amp;quot;)

(defun parse-grid (input)
  &amp;quot;Parse a string of input, fill a new grid with a coordinate number -&amp;gt; a cell (hash-table).
  Return: our new grid.&amp;quot;
  (loop :for char :across input
        :with grid := (make-grid)
        :for x :from 0
        :for cell := (cell char)
        :do
           ;; associate our grid at the X coordinate
           ;; with our new cell.
           ;; (setf … )
        :finally (return grid)))

;; try it:
#++
(parse-grid *input*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s only a simple example of the map mechanism that comes regurlarly in AOC.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the 3rd exercise that uses all of this.&lt;/p&gt;

&lt;h2 id=&#34;harder-puzzle-hash-tables-grid-coordinates&#34;&gt;Harder puzzle - hash-tables, grid, coordinates&lt;/h2&gt;

&lt;p&gt;This exercise comes from Advent Of Code 2024, day 06.
&lt;a href=&#34;https://adventofcode.com/2024/day/6&#34;&gt;https://adventofcode.com/2024/day/6&lt;/a&gt;
It&amp;rsquo;s an opportunity to use hash-tables.&lt;/p&gt;

&lt;p&gt;Read the puzzle there!
Try with your own input data!&lt;/p&gt;

&lt;p&gt;Here are the shortened instructions.&lt;/p&gt;

&lt;p&gt;The solutions are in another file, on my GitHub repository.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;;
;;; ********************************************************************
;;; WARN: this exercise migth be hard if you don&#39;t know about functions.
;;; ********************************************************************
;;;
;;; you can come back to it later.
;;; But, you can have a look, explore and get something out of it.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this exercise, we use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;;
;;; parameters
;;; functions
;;; recursivity
;;; &amp;amp;aux in a lambda list
;;; CASE
;;; return-from
;;; &amp;amp;key arguments
;;; complex numbers
;;; hash-tables
;;; the DICT notation (though optional)
;;; LOOPing on a list and on strings
;;; equality for characters
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For this puzzle, we make our life easier and we&amp;rsquo; use the DICT notation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(import &#39;serapeum:dict)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you know how to create a package, go for it.&lt;/p&gt;

&lt;p&gt;Please, quickload the STR library for this puzzle.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#++
(ql:quickload &amp;quot;str&amp;quot;)
;; Otherwise, see this as another exercise to rewrite the functions we use.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is your puzzle input:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; a string representing a grid, a map.
(defparameter *input* &amp;quot;....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...&amp;quot;)

;; the # represents an obstacle,
;; the ^ represents a guard that walks to the top of the grid.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When the guard encounters an obstacle, it turns 90 degrees right, and keeps walking.&lt;/p&gt;

&lt;p&gt;Our task is to count the number of distinct positions the guard will visit on the grid
before eventually leaving the area.&lt;/p&gt;

&lt;p&gt;We will have to:
- parse the grid into a data structure
  - preferably, an efficient data structures to hold coordinates. Indeed, AOC &lt;em&gt;real&lt;/em&gt; inputs are large.
- for each cell, note if it&amp;rsquo;s an obstacle, if that&amp;rsquo;s where the guard is, if the cell was already visited,
- count the number of visited cells.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; We&#39;ll represent a cell &amp;quot;object&amp;quot; by a hash-table.
;; With Serapeum&#39;s dict:
(defun cell (char &amp;amp;key guard visited)
  (dict :char char
        :guard guard
        :visited visited))

;; Our grid is a dict too.
;; We create a top-level variable, mainly for devel purposes.
(defvar *grid* (dict)
  &amp;quot;A hash-table to represent our grid. Associates a coordinate (complex number which represents the X and Y axis in the same number) to a cell (another hash-table).&amp;quot;)
;; You could use a DEFPARAMETER, like I did initially. But then, a C-c C-k (recompile current file) will erase its current value, and you might want or not want this.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For each coordinate, we associate a cell.&lt;/p&gt;

&lt;p&gt;What is a coordinate? We use a trick we saw in other people&amp;rsquo;s AOC solution,
to use a complex number.
Indeed, with its real and imaginary parts, it can represent both the X axis and the Y axis
&lt;em&gt;at the same time in the same number&lt;/em&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#|
;; Practice complex numbers:

(complex 1)
;; =&amp;gt; 1
(complex 1 1)
;; =&amp;gt; represented #C(1 1)

;; Get the imaginary part (let&#39;s say, the Y axis):
(imagpart #C(1 1))

;; the real part (X axis):
(realpart #C(1 1))

|#
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Look, we are tempted to go full object-oriented
and represent a &amp;ldquo;coordinate&amp;rdquo; object, a &amp;ldquo;cell&amp;rdquo; object and whatnot,
but it&amp;rsquo;s OK we can solve the puzzle with usual data structures.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Let&#39;s remember where our guard is.
(defvar *guard* nil
  &amp;quot;The guard coordinate. Mainly for devel purposes (IIRC).&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Task 1: parse the grid string&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We must parse the string to a hash-table of coordinates -&amp;gt; cells.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll write the main loop for you.
If you feel ready, take a go at it.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun parse-grid (input)
  &amp;quot;Parse INPUT (string) to a hash-table of coordinates -&amp;gt; cells.&amp;quot;
  ;; We start by iterating on each line.
  (loop :for line :in (str:lines input)
        ;; start another variable that tracks our loop iteration.
        ;; It it incremented by 1 at each loop by default.
        :for y :from 0  ;; up and down on the map, imagpart of our coordinate number.
        ;; The loop syntax with … = … creates a variable at the first iteration,
        ;; not at every iteration.
        :with grid = (dict)

        ;; Now iterate on each line&#39;s character.
        ;; A string is an array of characters,
        ;; so we use ACROSS to iterate on it. We use IN to iterate on lists.
        ;;
        ;; The Iterate library has the generic :in-sequence clause if that&#39;s your thing (with a speed penalty).
        :do (loop :for char :across line
                 :for x :from 0   ;; left to right on the map, realpart of our coordinate.
                 :for key := (complex x y)
                  ;; Create a new cell at each character.
                  :for cell := (cell char)
                  ;; Is this cell the guard at the start position?
                 :when (equal char #\^)
                   :do (progn
                         ;; Here, use SETF on GETHASH
                         ;; to set the :guard keyword of the cell to True.

                         (print &amp;quot;we saw the guard&amp;quot;)
                         ;; (setf (gethash … …) …)

                         ;; For devel purposes, we will also keep track of
                         ;; where our guard is with a top-level parameter.
                         (setf *guard* key)
                         )
                  :do
                     ;; Normal case:
                     ;; use SETF on GETHAH
                     ;; to associate this KEY to this CELL in our GRID.
                     (format t &amp;quot;todo: save the cell ~S in the grid&amp;quot; cell)
                  )
        :finally (return grid))
  )

;; devel: test and bind a top-level param for ease of debugging/instropection/poking around.
#++
(setf *grid* (parse-grid *input*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Task 2: walk our guard, record visited cells.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We have to move our guard on the grid, until it exits it.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll give you a couple utility functions.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun is-block (cell)
  &amp;quot;Is this cell an obstacle?&amp;quot;
  ;; accept a NIL, we&#39;ll stop the walk in the next iteration.
  (when cell
    (equal TODO #\#)))

;; We choose the write the 4 possible directions as :up :down :right :left.
;; See also:
;; exhaustiveness checking at compile-time:
;; https://dev.to/vindarel/compile-time-exhaustiveness-checking-in-common-lisp-with-serapeum-5c5i

(defun next-x (position direction)
  &amp;quot;From a position (complex number) and a direction, compute the next X.&amp;quot;
  (case direction
    (:up (realpart position))
    (:down (realpart position))
    (:right (1+ (realpart position)))
    (:left (1- (realpart position)))))

(defun next-y (position direction)
  &amp;quot;From a position (complex number) and a direction, compute the next Y.&amp;quot;
  (case direction
    (:up (1- (imagpart position)))
    (:down (1+ (imagpart position)))
    (:right (imagpart position))
    (:left (imagpart position))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the &amp;ldquo;big&amp;rdquo; function that moves the guard,
records were it went,
makes it rotate if it is against a block,
and iterates, until the guard goes out of the map.&lt;/p&gt;

&lt;p&gt;Read the puzzle instructions carefuly and write the &amp;ldquo;TODO&amp;rdquo; placeholders.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun walk (&amp;amp;key (grid *grid*) (input *input*)
               (position *guard*)
               (cell (gethash *guard* *grid*))  ;; todo: *grid* is used here. Fix it so we don&#39;t use a top-level variable, but only the grid given as a key argument.
               (direction :up)
               (count 0)
               ;; &amp;amp;aux notation: it saves a nested of LET bindings.
               ;; It&#39;s old style.
               ;; Those are not arguments to the function we pass around,
               ;; they are bindings inside the function body.
             &amp;amp;aux next-cell
               next-position
               obstacle-coming)
  &amp;quot;Recursively move the guard and annotate cells of our grid,
  count the number of visited cells.&amp;quot;

  ;; At each iteration, we study a new cell we take on our grid.
  ;; If we move the guard to a coordinate that doesn&#39;t exist in our grid,
  ;; we stop here.
  (unless cell
    (return-from walk count))

  ;; Look in the same direction first and see what we have.
  (setf next-position
        (complex (next-x position direction) (next-y position direction)))

  (setf next-cell (gethash next-position grid))

  ;; obstacle?
  (setf obstacle-coming (is-block next-cell))

  ;; then change direction.
  (when obstacle-coming
    (setf direction
          (case direction
            (:up :right)
            (:down :left)
            (:right :down)
            (:left :up))))

  ;; Count unique visited cells.
  ;; TODO
  (unless (print &amp;quot;if this CELL is visited...&amp;quot;)
      (incf count)
      ;; TODO set this cell as visited.
      (print &amp;quot;set this CELL to visited&amp;quot;)
    )

  ;; get our next position now.
  (setf next-position
        (complex (next-x position direction) (next-y position direction)))

  ;; This next cell may or may not be in our grid (NIL).
  (setf next-cell (gethash next-position grid))

  (walk :grid grid :input input
        :cell next-cell
        :position next-position
        :direction direction
        :count count))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and that&amp;rsquo;s how we solve the puzzle:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun part-1 (input)
  (walk :grid (parse-grid input)))

#++
(part-1 *input*)
;; 41
;; The right answer for this input.
;; In AOC, you have a bigger, custom puzzle input. This can lead to surprises.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;closing-words&#34;&gt;Closing words&lt;/h2&gt;

&lt;p&gt;Look at other people&amp;rsquo;s solutions too. For example, &lt;a href=&#34;https://github.com/ak-coram/advent/blob/main/2024/06.lisp&#34;&gt;ak-coram&amp;rsquo;s for our last exercise&lt;/a&gt; (using FSet). See how Screamer is used for day 06 by bo-tato (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1h94tfe/advent_of_code_2024_day_7_with_screamer_non/&#34;&gt;reddit&lt;/a&gt;). atgreen (ocicl, cl-tuition, cffi…) &lt;a href=&#34;https://www.reddit.com/r/adventofcode/comments/1h689qf/2024_day_4_solutions/m0ejih1/&#34;&gt;solution&lt;/a&gt; with a grid as a hash-table with complex numbers. lispm&amp;rsquo;s &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1h7ib2v/advent_of_code_2024_day_4_in_common_lisp_lispworks/&#34;&gt;day 04&lt;/a&gt; solution. Can you read all solutions?&lt;/p&gt;

&lt;p&gt;On other days, I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;alexandria&amp;rsquo;s &lt;code&gt;map-permutations&lt;/code&gt; for day 08 when you want… permutations. It doesn&amp;rsquo;t &amp;ldquo;cons&amp;rdquo; (what does that mean you ask? You didn&amp;rsquo;t follow my course ;) ). Read here: &lt;a href=&#34;https://dev.to/vindarel/advent-of-code-alexandrias-map-permutations-was-perfect-for-day-08-common-lisp-tip-16il&#34;&gt;https://dev.to/vindarel/advent-of-code-alexandrias-map-permutations-was-perfect-for-day-08-common-lisp-tip-16il&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;the library fare-memoization, to help in a recursive solution.&lt;/li&gt;
&lt;li&gt;to write math, use cmu-infix. When you spot 2 equations with 2 unknows, think &amp;ldquo;Cramer system&amp;rdquo;. This came up last year, so maybe not this year.&lt;/li&gt;
&lt;li&gt;with very large numbers: use double floats, as in &lt;code&gt;1.24d0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;least common multiple? &lt;code&gt;lcm&lt;/code&gt; is a built-in.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-str/?tab=readme-ov-file#match-experimental--new-in-feb-2024&#34;&gt;str:match&lt;/a&gt; can be a thing to parse strings.&lt;/li&gt;
&lt;li&gt;if you got &lt;a href=&#34;https://github.com/ciel-lang/CIEL/&#34;&gt;CIEL&lt;/a&gt; (CIEL Is an Extended Lisp), you have Alexandria, cl-str, Serapeum:dict and more libraries baked-in. It&amp;rsquo;s also an easy way to run Lisp scripts (with these dependencies) from the shell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See you and happy lisping!&lt;/p&gt;

&lt;p&gt;Your best resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;my course in videos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>🎥 ⭐ Learn Common Lisp data structures: 9 videos, 90 minutes of video tutorials to write efficient Lisp</title>
      <link>/blog/learn-lisp-data-structures-9-videos-90-minutes/</link>
      <pubDate>Tue, 25 Nov 2025 19:11:24 +0100</pubDate>
      
      <guid>/blog/learn-lisp-data-structures-9-videos-90-minutes/</guid>
      <description>

&lt;p&gt;It is with great pleasure and satisfaction that I published &lt;strong&gt;new
videos about Common Lisp data structures&lt;/strong&gt; on my course.&lt;/p&gt;

&lt;p&gt;The content is divided into &lt;strong&gt;9 videos&lt;/strong&gt;, for &lt;strong&gt;a total of 90
minutes&lt;/strong&gt;, plus &lt;strong&gt;exercises&lt;/strong&gt;, and comprehensive lisp snippets for each video so you can
practice right away.&lt;/p&gt;

&lt;p&gt;The total learning material on my course now accounts for 8.40 hours,
in 10 chapters and 61 videos, plus extras. You get to learn all the
essentials to be an efficient (Common Lisp) developer: &lt;strong&gt;CLOS&lt;/strong&gt; made
easy, &lt;strong&gt;macros&lt;/strong&gt;, error and condition handling, iteration, all about
functions, working with projects, etc. All the videos have english
subtitles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;learn more about this course (and why it&amp;rsquo;s a good idea to support me ;) ) on the GitHub page: &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos&#34;&gt;Common Lisp course in videos:
learn Lisp in videos (github)&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;and register here: &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=DATAISCODEISDATA&#34;&gt;🎥 Common Lisp programming course on
Udemy&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;if you are a student, drop me an email for a free link.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;You can refer to the course with &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;this
link&lt;/a&gt;
(with my referral).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=DATAISCODEISDATA&#34;&gt;&lt;img src=&#34;https://github.com/vindarel/common-lisp-course-in-videos/raw/master/announce.svg&#34; alt=&#34;&#34; title=&#34;Learn Lisp on my course with a -60% coupon&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#what-is-this-course-anyways&#34;&gt;What is this course anyways?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#course-outcome&#34;&gt;Course outcome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-content&#34;&gt;Chapter content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-words&#34;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;what-is-this-course-anyways&#34;&gt;What is this course anyways?&lt;/h2&gt;

&lt;p&gt;Hey, first look at what others say about it!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[My employees] said you do a better job of teaching than Peter Seibel&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ebbzry, CEO of VedaInc, August 2025 on Discord. O_o&lt;/p&gt;

&lt;p&gt;🔥 :D&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have done some preliminary Common Lisp exploration prior to this course but had a lot of questions regarding practical use and development workflows. This course was amazing for this! I learned a lot of useful techniques for actually writing the code in Emacs, as well as conversational explanations of concepts that had previously confused me in text-heavy resources. Please keep up the good work and continue with this line of topics, it is well worth the price!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;@Preston, October of 2024 &amp;lt;3&lt;/p&gt;

&lt;p&gt;Now another feedback is that also according to learners, the areas I
could improve are: give more practice activities, make the videos more
engaging.&lt;/p&gt;

&lt;p&gt;I worked on both. With the experience and my efforts, my flow should
be more engaging. My videos always have on-screen annotations about
what I&amp;rsquo;m doing or have complementary information. They are edited to
be dynamic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You have 9 freely-available videos in the course&lt;/strong&gt; so you can judge
by yourself (before leaving an angry comment ;) ). Also be aware that
&lt;em&gt;the course is not for total beginners in a &amp;ldquo;lisp&amp;rdquo; language&lt;/em&gt;. We see
the basics (evaluation model, syntax…), but quickly. Then we dive in
&amp;ldquo;the Common Lisp way&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;I also created &lt;strong&gt;more practice activities.&lt;/strong&gt; For this chapter on data
structures, each video comes with its usual set of extensive lisp
snippets to practice (for example, I give you a lisp file with all
sequence functions, showing their common use and some gotchas), plus
&lt;strong&gt;3 exercises&lt;/strong&gt;, heavily annotated. Given the time of the year we are
on, I prepare you for Advent Of Code :) I drive you into how you
can put your knowledge in use to solve its puzzles. If you have access to the course
and you are somewhat advanced, look at the new exercise of section 6.&lt;/p&gt;

&lt;p&gt;Enough talk, what will you learn?&lt;/p&gt;

&lt;h2 id=&#34;course-outcome&#34;&gt;Course outcome&lt;/h2&gt;

&lt;p&gt;The goals were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;give you an &lt;strong&gt;overview of the available data structures&lt;/strong&gt; in Common Lisp (lists and the cons cell, arrays, hash-tables, with a mention of trees an sets)&lt;/li&gt;
&lt;li&gt;teach you how things work, don&amp;rsquo;t read everything for you. I show you
the usual sequence functions, but I don&amp;rsquo;t spend an hour listing all of
them. Instead I give you pointers to a reference and a lisp file with all of
them.&lt;/li&gt;
&lt;li&gt;give pointers on &lt;strong&gt;where is Common Lisp different&lt;/strong&gt; and &lt;strong&gt;where is
Common Lisp similar&lt;/strong&gt; to any other language. For example, we discuss the
time complexity of list operations vs. arrays.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;teach common errors&lt;/strong&gt;, such as using &lt;code&gt;&#39;(1 2 3)&lt;/code&gt; with a quote
instead of the list constructor function, and how this can lead to
subtle bugs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;make your life easier&lt;/strong&gt;: working with bare-bones hash-tables is too
awkward for my taste, and was specially annoying as a beginner. I
give you workarounds, in pure CL and with third-party libraries.

&lt;ul&gt;
&lt;li&gt;🆓 &lt;code&gt;this video is free for everybody&lt;/code&gt;, hell yes, this was really annoying to me.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;present the ecosystem&lt;/strong&gt; and &lt;strong&gt;discuss style&lt;/strong&gt;: for example I point you to purely-functional data-structures libraries, we see how to deal with functions being destructive or not destructive and how to organize your functions accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, suppose you followed this chapter, the one about functions, and a
couple videos on iteration: &lt;strong&gt;you are ready&lt;/strong&gt; to write &lt;strong&gt;efficient solutions&lt;/strong&gt;
to Advent Of Code.&lt;/p&gt;

&lt;h2 id=&#34;chapter-content&#34;&gt;Chapter content&lt;/h2&gt;

&lt;p&gt;3.1 Intro &lt;strong&gt;[🆓 FREE FOR ALL]&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Common Lisp has more than lists: hash-tables (aka dictionaries), arrays, as well as sets and tree operations. Linked lists are made of &amp;ldquo;CONS&amp;rdquo; cells. You should adopt a functional style in your own functions, and avoid the built-ins that mutate data. We see how, and I give you more pointers for modern Common Lisp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;3.2 Lists: create lists, plists, alists&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: how to create lists (proper lists, plists and alists). A first warning about the &amp;lsquo;(1 2 3) notation with a quote.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;PRACTICE: list creation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.3 Lists (2): lists manipulation&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lists, continued. What we see: how to access elements: FIRST, REST, LAST, NTH…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;PRACTICE: accessing sequences elements&lt;/li&gt;
&lt;li&gt;PRACTICE: sequences manipulation functions&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/blob/master/exercises/chapter%20-%20data%20structures/AOC-2024-day01.lisp&#34;&gt;EXERCISE: parse, sort, compute. AOC day 01.&lt;/a&gt; (hard for total beginners. Have a look, take at least something out of it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.4 Equality - working with strings gotcha&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: explanation of the different equality functions and why knowing this is necessary when working with strings. EQ, EQL, EQUAL, EQUALP (and STRING= et all) explained. Which is too low-level, which you&amp;rsquo;ll use most often.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;PRACTICE: using equality predicates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.5 Vectors and arrays&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: vectors (one-dimensional arrays), multi-dimensional arrays, VECTOR-PUSH[-EXTEND], the fill-pointer, adjustable arrays, AREF, VECTOR-POP, COERCE, iteration across arrays (LOOP, MAP).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;EXERCISE: compare lists and vectors access time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.6 The CONS cell&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &amp;ldquo;CONS cell&amp;rdquo; is the building block of Common Lisp&amp;rsquo;s (linked) lists. What do &amp;ldquo;cons&amp;rdquo;, &amp;ldquo;car&amp;rdquo; and &amp;ldquo;cdr&amp;rdquo; even mean?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;3.7 The &lt;code&gt;:test&lt;/code&gt; and &lt;code&gt;:keys&lt;/code&gt; arguments&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All CL built-in functions accept a :TEST and :KEY argument. They are great. What we see: when and how to use them, when working with strings and with compound objects (lists of lists, lists of structs, etc).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;3.8 Hash-tables and fixing their two ergonomic flaws &lt;strong&gt;[🆓 FREE FOR ALL]&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hash-tables (dictionaries, hash maps etc) are efficient key-value stores. However, as a newcomer, I had them in gripe. They were not easy enough to work with. I show you everything that&amp;rsquo;s needed to work with hash-tables, and my best solution for better ergonomics.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;PRACTICE: the video snippet to create hash-tables, access and set content, use Alexandria, Serapeum&amp;rsquo;s &lt;code&gt;dict&lt;/code&gt; notation, iterate on keys and values, serialize a HT to a file and read its content back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3.9 Using QUOTE to create lists is NOT THE SAME as using the LIST function. Gotchas and solution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thinking that &amp;lsquo;(1 2 3) is the same as (list 1 2 3) is a rookie mistake and can lead to subtle bugs. Demo, explanations and simple rule to follow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At last, EXERCISE of section 6: real Advent Of Code puzzle.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;;
;;; In this exercise, we use:
;;;
;;; top-level variables
;;; functions
;;; recursivity
;;; &amp;amp;aux in a lambda list
;;; CASE
;;; return-from
;;; &amp;amp;key arguments
;;; complex numbers
;;; hash-tables
;;; the DICT notation (optional)
;;; LOOPing on a list and on strings
;;; equality
;;; characters literal notation

(defparameter *input* &amp;quot;....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;closing-words&#34;&gt;Closing words&lt;/h2&gt;

&lt;p&gt;Thanks for your support, thanks to everybody who took the course or who shared it, and for your
encouragements.&lt;/p&gt;

&lt;p&gt;If you wonder why I create a paid course and you regret it isn&amp;rsquo;t totally free (my
past me would def wonder), see some details on the &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/clos-tutorial-in-9-videos-1h22min--read-the-sources-of-hunchentoot-and-kandria/&#34;&gt;previous announce&lt;/a&gt;. The short answer is: I &lt;em&gt;also&lt;/em&gt; contribute free resources.&lt;/p&gt;

&lt;p&gt;Keep lisping and see you around: improving the Cookbook or Lem, on the Fediverse, reddit and Discord…&lt;/p&gt;

&lt;p&gt;What should be next: how the Cookbook PDF quality was greatly improved thanks to Typst. Stay tuned.&lt;/p&gt;

&lt;p&gt;Oh, a last shameless plug: since Ari asked me at the beginning of the
year, I now do 1-1 Lisp coaching sessions. We settled on 40 USD an
hour. Drop me an email! &lt;code&gt;(concatenate &#39;string &amp;quot;vindarel&amp;quot; &amp;quot;@&amp;quot; &amp;quot;mailz&amp;quot; &amp;quot;.&amp;quot; &amp;quot;org&amp;quot;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🎥 &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;Common Lisp course in videos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🕊&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lisp tutorial: variables. defparameter vs defvar, let/let* and lexical scope, unbound variables, style guidelines</title>
      <link>/blog/lisp-tutorial-variables/</link>
      <pubDate>Tue, 16 Sep 2025 23:47:24 +0200</pubDate>
      
      <guid>/blog/lisp-tutorial-variables/</guid>
      <description>

&lt;p&gt;Lisp newcomers, I still care about you ;) A section on variables was missing on the Cookbook, here it is.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As usual, this is &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/variables.html&#34;&gt;best read on the Common Lisp Cookbook&lt;/a&gt;. This is where it will get updates and fixes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The Cookbook has many contributors. You can contribute too. I myself
mostly contributed (out of frustration) as I was discovering Common
Lisp, the language and the ecosystem. It&amp;rsquo;s been years now, but I still take care of it
because I like it, and thanks to your tips. As I don&amp;rsquo;t have a salary
nor a million-dollar company, I do appreciate them. I&amp;rsquo;m on &lt;a href=&#34;https://github.com/sponsors/vindarel/&#34;&gt;github
sponsors too&lt;/a&gt;. Thank you!&lt;/p&gt;

&lt;p&gt;Also, I can now generate a good-quality PDF thanks to Typst and Pandoc. Stay tuned.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;So, you are writing your first Common Lisp program (again, welcome!) and
you want to declare variables. What are your options?&lt;/p&gt;

&lt;p&gt;When in doubt, use &lt;code&gt;defparameter&lt;/code&gt; for top-level parameters.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;let*&lt;/code&gt; for lexical scope:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let* ((a 2)
       (square (* a a)))
   (format t &amp;quot;the square of ~a is ~a&amp;quot; a square))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Use &lt;code&gt;setf&lt;/code&gt; to change them.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#defparameter-top-level-variables&#34;&gt;&lt;code&gt;defparameter&lt;/code&gt;: top-level variables&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#redefining-a-defparameter&#34;&gt;redefining a defparameter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#defvar-no-redefinition&#34;&gt;&lt;code&gt;defvar&lt;/code&gt;: no redefinition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-earmuff-convention&#34;&gt;The &amp;ldquo;*earmuff*&amp;rdquo; convention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#global-variables-are-created-in-the-dynamic-scope&#34;&gt;Global variables are created in the &amp;ldquo;dynamic scope&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#setf-change-values&#34;&gt;&lt;code&gt;setf&lt;/code&gt;: change values&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#let-let-create-lexical-scopes&#34;&gt;&lt;code&gt;let&lt;/code&gt;, &lt;code&gt;let*&lt;/code&gt;: create lexical scopes&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#let-vs-let&#34;&gt;&lt;code&gt;let&lt;/code&gt; vs &lt;code&gt;let*&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#setf-inside-let&#34;&gt;setf inside let&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#when-you-dont-use-defined-variables&#34;&gt;When you don&amp;rsquo;t use defined variables&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#unbound-variables&#34;&gt;Unbound variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#global-variables-are-thread-safe&#34;&gt;Global variables are thread safe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#addendum-defconstant&#34;&gt;Addendum: &lt;code&gt;defconstant&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#guidelines-and-best-practices&#34;&gt;Guidelines and best practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;defparameter-top-level-variables&#34;&gt;&lt;code&gt;defparameter&lt;/code&gt;: top-level variables&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;defparameter&lt;/code&gt; to declare top-level variables, like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;me&amp;quot;)

(defun hello (&amp;amp;optional name)
  &amp;quot;Say hello.&amp;quot;
  (format t &amp;quot;Hello ~a!&amp;quot; (or name *name*)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;defparameter&lt;/code&gt; accepts an optional third argument: the variable&amp;rsquo;s docstring:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;me&amp;quot;
   &amp;quot;Default name to say hello to.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The inline docstrings are an important part of the Common Lisp
interactive experience. You will encounter them during your coding
sessions (and we lispers usually keep our Lisp running for a long
time). In Emacs and Slime, you can ask for a symbol&amp;rsquo;s docstring with
&lt;code&gt;C-c C-d d&lt;/code&gt; (Alt-x &lt;code&gt;slime-describe-symbol&lt;/code&gt;). You can also ask for a
docstring programmatically:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(documentation &#39;*name* &#39;variable)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We ask the documentation of the &lt;code&gt;*name*&lt;/code&gt; &lt;em&gt;symbol&lt;/em&gt;, not what it holds,
hence the quote in &lt;code&gt;&#39;*name*&lt;/code&gt; (which is short for &lt;code&gt;(quote
*name*)&lt;/code&gt;. Another &amp;ldquo;doc-type&amp;rdquo; is &lt;code&gt;&#39;function&lt;/code&gt;. See: in Common Lisp,
variables and functions live in different &amp;ldquo;namespaces&amp;rdquo;, and it shows
here.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll mention the &lt;code&gt;defparameter&lt;/code&gt; form with no value below.&lt;/p&gt;

&lt;h3 id=&#34;redefining-a-defparameter&#34;&gt;redefining a defparameter&lt;/h3&gt;

&lt;p&gt;A Common Lisp coding session is usually long-lasting and very
interactive. We leave a Lisp running and we interact with it while we
work. This is done with Emacs and Slime, Vim, Atom and SLIMA, VSCode
and Alive, Lem… and more editors, or from the terminal.&lt;/p&gt;

&lt;p&gt;That means that you can do this:&lt;/p&gt;

&lt;p&gt;1- write a first defparameter&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;me&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;either write this in the REPL, either write this in a .lisp file and
compile+load it with a shortcut (&lt;code&gt;C-c C-c&lt;/code&gt; (Alt-x &lt;code&gt;slime-compile-defun&lt;/code&gt;) in
Slime on this expression, or &lt;code&gt;C-c C-k&lt;/code&gt; (Alt-x &lt;code&gt;slime-compile-and-load-file&lt;/code&gt;)
to compile and load everything you have in the current buffer). If you
work from a simple terminal REPL, you can &lt;code&gt;(load …)&lt;/code&gt; a .lisp file.&lt;/p&gt;

&lt;p&gt;Now the &lt;code&gt;*name*&lt;/code&gt; variable exists in the running image.&lt;/p&gt;

&lt;p&gt;2- edit the defparameter line:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;you&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and load the changes the same way: either with the REPL, or with a
&lt;code&gt;C-c C-c&lt;/code&gt;. Now, the &lt;code&gt;*name*&lt;/code&gt; variable has a new value, &amp;ldquo;you&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;defvar&lt;/code&gt; wouldn&amp;rsquo;t be redefined.&lt;/p&gt;

&lt;h2 id=&#34;defvar-no-redefinition&#34;&gt;&lt;code&gt;defvar&lt;/code&gt;: no redefinition&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;defvar&lt;/code&gt; defines top-level &lt;em&gt;variables&lt;/em&gt; and protects them from redefinition.&lt;/p&gt;

&lt;p&gt;When you re-load a &lt;code&gt;defvar&lt;/code&gt;, it doesn&amp;rsquo;t erase the current value, you
must use &lt;code&gt;setf&lt;/code&gt; for this.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *names-cache* (list)
  &amp;quot;Store a list of names we said \&amp;quot;hello\&amp;quot; to.&amp;quot;)

(defun hello (&amp;amp;optional (name *name*))
   (pushnew name *names-cache* :test #&#39;string-equal)
   (format t &amp;quot;hello ~a!&amp;quot; name))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s see it in use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (hello)
hello you!
NIL
CL-USER&amp;gt; *names-cache*
(&amp;quot;you&amp;quot;)
CL-USER&amp;gt; (hello &amp;quot;lisper&amp;quot;)
hello lisper!
NIL
CL-USER&amp;gt; *names-cache*
(&amp;quot;lisper&amp;quot; &amp;quot;you&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What happens to &lt;code&gt;*names-cache*&lt;/code&gt; if you redefine the &lt;code&gt;defvar&lt;/code&gt; line
(with &lt;code&gt;C-c C-c&lt;/code&gt;, or &lt;code&gt;C-c C-k&lt;/code&gt;, or on the REPL…)?&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t change and &lt;em&gt;that is a good thing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Indeed, this variable isn&amp;rsquo;t a user-visible parameter, it doesn&amp;rsquo;t have
an immediate use, but it is important for the program correctness, or
strength, etc. Imagine it holds the cache of your webserver: you don&amp;rsquo;t
want to erase it when you load new code. During development, we hit a
lot &lt;code&gt;C-c C-k&lt;/code&gt; to reload the current file, we can as well reload our
running app in production, but there are certain things we want
untouched. If it is a database connection, you don&amp;rsquo;t want to set it
back to nil, and connect again, everytime you compile your code.&lt;/p&gt;

&lt;p&gt;You must use &lt;code&gt;setf&lt;/code&gt; to change a defvar&amp;rsquo;s variable value.&lt;/p&gt;

&lt;h2 id=&#34;the-earmuff-convention&#34;&gt;The &amp;ldquo;*earmuff*&amp;rdquo; convention&lt;/h2&gt;

&lt;p&gt;See how we wrote &lt;code&gt;*name*&lt;/code&gt; in-between &amp;ldquo;*earmuffs*&amp;rdquo;. That is an
important convention, that helps you not override top-level variables
in lexical scopes.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter name &amp;quot;lisper&amp;quot;)

;; later…
(let ((name &amp;quot;something else&amp;quot;))
   ;;  ^^^ overrides the top-level name. This will cause bugs.
   …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This becomes a feature only when using earmuffs:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *db-name* &amp;quot;db.db&amp;quot;)

(defun connect (&amp;amp;optional (db-name *db-name*))
  (sqlite:connect db-name))

(let ((*db-name* &amp;quot;another.db&amp;quot;))
  (connect))
  ;;^^^^  its db-name optional parameter, which defaults to *db-name*, now sees &amp;quot;another.db&amp;quot;.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By the way, for such a use-case, you will often find &lt;code&gt;with-…&lt;/code&gt; macros
that abstract the &lt;code&gt;let&lt;/code&gt; binding.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-db &amp;quot;another.db&amp;quot;
  (connect))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By the way again, an
&lt;a href=&#34;https://www.wordreference.com/definition/earmuff&#34;&gt;earmuff&lt;/a&gt; is a thing
that covers the ears (but only the ears) in winter. You might have
seen it in movies more than in reality. The lasting word is: take care
of yourself, stay warm and use earmuffs.&lt;/p&gt;

&lt;h2 id=&#34;global-variables-are-created-in-the-dynamic-scope&#34;&gt;Global variables are created in the &amp;ldquo;dynamic scope&amp;rdquo;&lt;/h2&gt;

&lt;p&gt;Our top-level parameters and variables are created in the so-called
&lt;em&gt;dynamic scope&lt;/em&gt;. They can be accessed from anywhere else: from
function definitions (as we did), in &lt;code&gt;let&lt;/code&gt; bindings, etc.&lt;/p&gt;

&lt;p&gt;In Lisp, we also say these are &lt;a href=&#34;https://cl-community-spec.github.io/pages/Dynamic-Variables.html&#34;&gt;&lt;em&gt;dynamic variables&lt;/em&gt; or &lt;em&gt;special&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It could also be possible to create one from anywhere by &lt;em&gt;proclaiming&lt;/em&gt;
it &amp;ldquo;special&amp;rdquo;. It really isn&amp;rsquo;t the thing you do everydays but, you
know, in Lisp everything&amp;rsquo;s possible ;)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A dynamic variable can be referenced outside the dynamic extent of a form that binds it. Such a variable is sometimes called a &amp;ldquo;global variable&amp;rdquo; but is still in all respects just a dynamic variable whose binding happens to exist in the global environment rather than in some dynamic environment. [Hyper Spec]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;setf-change-values&#34;&gt;&lt;code&gt;setf&lt;/code&gt;: change values&lt;/h2&gt;

&lt;p&gt;Any variable can be changed with &lt;code&gt;setf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf *name* &amp;quot;Alice&amp;quot;)
;; =&amp;gt; &amp;quot;Alice&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It returns the new value.&lt;/p&gt;

&lt;p&gt;Actually, &lt;code&gt;setf&lt;/code&gt; accepts &lt;em&gt;pairs&lt;/em&gt; of value, variable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf *name* &amp;quot;Bob&amp;quot;
      *db-name* &amp;quot;app.db&amp;quot;)
;; =&amp;gt; &amp;quot;app.db&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It returned the last value.&lt;/p&gt;

&lt;p&gt;What happens if you &lt;code&gt;setf&lt;/code&gt; a variable that wasn&amp;rsquo;t declared yet? It
generally works but you have a warning:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; in SBCL 2.5.8
CL-USER&amp;gt; (setf *foo* &amp;quot;foo&amp;quot;)
; in: SETF *FOO*
;     (SETF CL-USER::*FOO* &amp;quot;foo&amp;quot;)
;
; caught WARNING:
;   undefined variable: CL-USER::*FOO*
;
; compilation unit finished
;   Undefined variable:
;     *FOO*
;   caught 1 WARNING condition
&amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We see the returned &amp;ldquo;foo&amp;rdquo;, so it worked. Please declare variables with
&lt;code&gt;defparameter&lt;/code&gt; or &lt;code&gt;defvar&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s read the full &lt;code&gt;setf&lt;/code&gt; docstring because it&amp;rsquo;s interesting:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-txt&#34;&gt;Takes pairs of arguments like SETQ. The first is a place and the second
is the value that is supposed to go into that place. Returns the last
value. The place argument may be any of the access forms for which SETF
knows a corresponding setting form.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that &lt;code&gt;setq&lt;/code&gt; is another macro, but now seldom used, because &lt;code&gt;setf&lt;/code&gt;
works on more &amp;ldquo;places&amp;rdquo;. You can setf functions and many things.&lt;/p&gt;

&lt;h2 id=&#34;let-let-create-lexical-scopes&#34;&gt;&lt;code&gt;let&lt;/code&gt;, &lt;code&gt;let*&lt;/code&gt;: create lexical scopes&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;let&lt;/code&gt; lets you define variables in a limited scope, or override top-level variables temporarily.&lt;/p&gt;

&lt;p&gt;Below, our two variables only exist in-between the parenthesis of the &lt;code&gt;let&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let* ((a 2)
       (square (* a a)))
   (format t &amp;quot;the square of ~a is ~a&amp;quot; a square))
   ;; so far so good

(format t &amp;quot;the value of a is: ~a&amp;quot; a)
;; =&amp;gt; ERROR: the variable A is unbound
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;ldquo;unbound&amp;rdquo; means the variable is bound to nothing, not even to NIL. Its
symbol may exist, but it isn&amp;rsquo;t associated to anything.&lt;/p&gt;

&lt;p&gt;Just after the scope formed by the &lt;code&gt;let&lt;/code&gt;, the variables &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;square&lt;/code&gt; don&amp;rsquo;t exist anymore.&lt;/p&gt;

&lt;p&gt;When the Lisp reader reads the &lt;code&gt;format&lt;/code&gt; expression, it reads a &lt;code&gt;a&lt;/code&gt;
symbol, which now exists in the global environment, but it isn&amp;rsquo;t bound.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Food for thought: the fact to write a variable name and have the Lisp reader read it creates the symbol, but doesn&amp;rsquo;t bind it to anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our two variables can be accessed by any form inside the &lt;code&gt;let&lt;/code&gt; binding. If we
create a second &lt;code&gt;let&lt;/code&gt;, its &lt;em&gt;environment&lt;/em&gt; inherits the previous one (we
see variables declared above, fortunately!).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;test&amp;quot;)

(defun log (square)
  (format t &amp;quot;name is ~s and square is ~a&amp;quot; *name* square))

(let* ((a 2)
       (square (* a a)))
  ;; inside first environment
  (let ((*name* &amp;quot;inside let&amp;quot;))
    ;; inside second environment,
    ;; we access the dynamic scope.
    (log square)))
;;  =&amp;gt; name is &amp;quot;inside let&amp;quot; and square is 4
;;  =&amp;gt; NIL

(print *name*)
;; =&amp;gt; &amp;quot;test&amp;quot;
;;    ^^^^ outside the let, back to the dynamic scope&#39;s value.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We could also define a function inside a let, so that this function
definition &amp;ldquo;sees&amp;rdquo; a binding from a surrounding let at compile
time. This is a closure and it&amp;rsquo;s for the chapter on functions.&lt;/p&gt;

&lt;p&gt;A &amp;ldquo;lexical scope&amp;rdquo; is simply&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a scope that is limited to a spatial or textual region within the establishing form. &amp;ldquo;The names of parameters to a function normally are lexically scoped.&amp;rdquo; [Hyper Spec]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, the scope of a variable is determined by its position
in the source code. It&amp;rsquo;s today&amp;rsquo;s best practice. It&amp;rsquo;s the least
surprising way of doing: you can &lt;em&gt;see&lt;/em&gt; the scope by looking at the
source code.&lt;/p&gt;

&lt;h3 id=&#34;let-vs-let&#34;&gt;&lt;code&gt;let&lt;/code&gt; vs &lt;code&gt;let*&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;By the way, what is the syntax of &lt;code&gt;let&lt;/code&gt; and what is the difference with &lt;code&gt;let*&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let*&lt;/code&gt; lets you declare variables that depend on each other.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let&lt;/code&gt;&amp;rsquo;s basic use is to declare a list of variables with no initial
values. They are initialized to &lt;code&gt;nil&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let (variable1 variable2 variable3) ;; variables are initialized to nil by default.
  ;; use them here
  …)

;; Example:
(let (a b square)
  (setf a 2)
  (setf square (* a a))
  (list a b square))
;; =&amp;gt; (2 NIL 4)

;; exactly the same:
(let (a
      b
      square)
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can give default values by using &amp;ldquo;pairs&amp;rdquo; of elements, as in &lt;code&gt;(a 2)&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((a 2)     ;; &amp;lt;-- initial value
       square)  ;; &amp;lt;-- no &amp;quot;pair&amp;quot; but still one element: defaults to NIL.
  (setf square (* a a))
  (list a square))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, there are two &lt;code&gt;((&lt;/code&gt; in a row! This is the syntax of Common
Lisp. You don&amp;rsquo;t need to count them. What appears after a &lt;code&gt;let&lt;/code&gt; is
variable definitions. Usually, one per line.&lt;/p&gt;

&lt;p&gt;The let&amp;rsquo;s logic is in the body, with a meaningful indentation. You can
read Lisp code based on indentation. If the project you are looking at
doesn&amp;rsquo;t respect that, it is a low quality project.&lt;/p&gt;

&lt;p&gt;Observe that we kept &lt;code&gt;square&lt;/code&gt; to nil. We want it to be the square of
&lt;code&gt;a&lt;/code&gt;, so can we do this?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((a 2)
      (square (* a a))) ;; WARN:
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can&amp;rsquo;t do that here, this is the limitation of &lt;code&gt;let&lt;/code&gt;. You need &lt;code&gt;let*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You could write two &lt;code&gt;let&lt;/code&gt;s:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((a 2))
  (let ((square (* a a)))
    (list a square)))
;; =&amp;gt; (2 4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is equivalent to &lt;code&gt;let*&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let* ((a 2)
       (square (* a a)))
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;let&lt;/code&gt; is to declare variables that don&amp;rsquo;t depend on each other, &lt;code&gt;let*&lt;/code&gt;
is to declare variables which are read one after the other and where
one can depend on a &lt;em&gt;previous&lt;/em&gt; one.&lt;/p&gt;

&lt;p&gt;This is &lt;em&gt;not&lt;/em&gt; valid:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let* ((square (* a a))  ;; WARN!
       (a 2))
   (list a square))
;; =&amp;gt; debugger:
;; The variable A is unbound.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The error message is clear. At the time of reading &lt;code&gt;(square (* a a))&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; is unknown.&lt;/p&gt;

&lt;h3 id=&#34;setf-inside-let&#34;&gt;setf inside let&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s make it even clearer: you can &lt;code&gt;setf&lt;/code&gt; any value that is
&lt;em&gt;shadowed&lt;/em&gt; in a &lt;code&gt;let&lt;/code&gt; binding, once outside the let, the variables are
back to the value of the current &lt;em&gt;environment&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We know this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;test&amp;quot;)

(let ((*name* &amp;quot;inside let&amp;quot;))
  (format t &amp;quot;*name* inside let: ~s&amp;quot; *name*))
;; =&amp;gt; *name* inside let: &amp;quot;inside let&amp;quot;

(format t &amp;quot;*name* outside let: ~s&amp;quot; *name*)
;; =&amp;gt; *name* outside let: &amp;quot;test&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we setf a dynamic parameter that was shadowed by a let binding:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *name* &amp;quot;test&amp;quot;)

(defun change-name ()
   ;; bad style though,
   ;; try to not mutate variables inside your functions,
   ;; but take arguments and return fresh data structures.
   (setf *name* &amp;quot;set!&amp;quot;))
   ;;    ^^^^^ from the dynamic environment, or from a let lexical scope.

(let ((*name* &amp;quot;inside let&amp;quot;))
  (change-name)
  (format t &amp;quot;*name* inside let: ~s&amp;quot; *name*))
;; =&amp;gt; *name* inside let: &amp;quot;set!&amp;quot;

(format t &amp;quot;*name* outside let: ~s&amp;quot; *name*)
;; =&amp;gt; *name* outside let: &amp;quot;test&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;when-you-don-t-use-defined-variables&#34;&gt;When you don&amp;rsquo;t use defined variables&lt;/h3&gt;

&lt;p&gt;Read your compiler&amp;rsquo;s warnings :)&lt;/p&gt;

&lt;p&gt;Below, it tells us that &lt;code&gt;b&lt;/code&gt; is defined but never used. SBCL is pretty
good at giving us useful warnings at &lt;em&gt;compile time&lt;/em&gt; (every time you
hit &lt;code&gt;C-c C-c&lt;/code&gt; (compile and load the expression at point), &lt;code&gt;C-c C-k&lt;/code&gt;
(the whole file) or use &lt;code&gt;load&lt;/code&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let (a b square)
  (list a square))
;; =&amp;gt;
; caught STYLE-WARNING:
;   The variable B is defined but never used.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example works in the REPL because SBCL&amp;rsquo;s REPL always compiles expressions.&lt;/p&gt;

&lt;p&gt;This may vary with your implementation.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s great to catch typos!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let* ((a 2)
       (square (* a a)))
  (list a squale))
  ;;         ^^^ typo
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you compile this in a .lisp file (or in a &lt;code&gt;Alt-x slime-scratch&lt;/code&gt; lisp buffer), you
will have two warnings, and your editor will underline each in two
different colors:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://lispcookbook.github.io/cl-cookbook/assets/let-example-squale.png&#34; alt=&#34;&#34; title=&#34;A decent editor highlights compilation warnings.&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first, &amp;ldquo;square&amp;rdquo; is defined but never used&lt;/li&gt;
&lt;li&gt;second, &amp;ldquo;squale&amp;rdquo; is an undefined variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run the snippet in the REPL, you will get the two warnings but,
because the snippet is run, you will see the interactive debugger
with the error &amp;ldquo;The variable SQUALE is unbound&amp;rdquo;.&lt;/p&gt;

&lt;h2 id=&#34;unbound-variables&#34;&gt;Unbound variables&lt;/h2&gt;

&lt;p&gt;&amp;ldquo;unbound&amp;rdquo; variables were not bound to anything, not even nil. Their
symbol might exist, but they have no associated value.&lt;/p&gt;

&lt;p&gt;You can create such variables like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *connection*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This &lt;code&gt;defparameter&lt;/code&gt; form is correct. You didn&amp;rsquo;t give any default
value: the parameter is unbound.&lt;/p&gt;

&lt;p&gt;You can check if a variable (or a function) is bound with &lt;code&gt;boundp&lt;/code&gt; (or
&lt;code&gt;fboundp&lt;/code&gt;). The &lt;code&gt;p&lt;/code&gt; is for &amp;ldquo;predicate&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;You can make a variable (or function) unbound with &lt;code&gt;makunbound&lt;/code&gt; (or &lt;code&gt;fmakunbound&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&#34;global-variables-are-thread-safe&#34;&gt;Global variables are thread safe&lt;/h2&gt;

&lt;p&gt;Don&amp;rsquo;t be afraid of accessing and set-ing global bindings in
threads. Each thread will have its own copy of the
variable. Consequently, you can bind them to other values with &lt;code&gt;let&lt;/code&gt;
bindings, etc. That&amp;rsquo;s good.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s only if you want one single source of truth that you&amp;rsquo;ll have to
share the variable between threads and where the danger lies. You can
use a lock (very easy), but that&amp;rsquo;s all another topic.&lt;/p&gt;

&lt;h2 id=&#34;addendum-defconstant&#34;&gt;Addendum: &lt;code&gt;defconstant&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;defconstant&lt;/code&gt; is here to say something is a constant and is not
supposed to change, but in practice &lt;code&gt;defconstant&lt;/code&gt; is annoying. Use
&lt;code&gt;defparameter&lt;/code&gt;, and add a convention with a new style of earmuffs:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter +pi+ pi
  &amp;quot;Just to show that pi exists but has no earmuffs. Now it does. You shouldn&#39;t change a variable with +-style earmuffs, it&#39;s a constant.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;defconstant&lt;/code&gt; is annoying because, at least on SBCL, it can&amp;rsquo;t be
redefined without asking for validation through the interactive
debugger, which we may often do during development, and its default
test is &lt;code&gt;eql&lt;/code&gt;, so give it a string and it will always think that the
constant was redefined. Look (evaluate each line one by one in order):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defconstant +best-lisper+ :me)
;; so far so good.

(defconstant +best-lisper+ :me)
;; so far so good: we didn&#39;t redefine anything.

(defconstant +best-lisper+ :you)
;; =&amp;gt; the constant is being redefined, we get the interactive debugger (SBCL):

The constant +BEST-LISPER+ is being redefined (from :ME to :YOU)
   [Condition of type SB-EXT:DEFCONSTANT-UNEQL]
See also:
  Common Lisp Hyperspec, DEFCONSTANT [:macro]
  SBCL Manual, Idiosyncrasies [:node]

Restarts:
 0: [CONTINUE] Go ahead and change the value.
 1: [ABORT] Keep the old value.
 2: [RETRY] Retry SLIME REPL evaluation request.
 3: [*ABORT] Return to SLIME&#39;s top level.
 4: [ABORT] abort thread (#&amp;lt;THREAD tid=573581 &amp;quot;repl-thread&amp;quot; RUNNING {120633D123}&amp;gt;)

;; =&amp;gt; presse 0 (zero) or click on the &amp;quot;Continue&amp;quot; restart to accept changing the value.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With constants as strings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defconstant +best-name+ &amp;quot;me&amp;quot;)
;; so far so good, we create a new constant.

(defconstant +best-name+ &amp;quot;me&amp;quot;)
;; =&amp;gt; interactive debugger!!

The constant +BEST-NAME+ is being redefined (from &amp;quot;me&amp;quot; to &amp;quot;me&amp;quot;)
…
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you will see in the equality chapter, two strings are not equal by
&lt;code&gt;eql&lt;/code&gt; that is a low-level equality operator (think pointers), they are
&lt;code&gt;equal&lt;/code&gt; (or &lt;code&gt;string-equal&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This is &lt;code&gt;defconstant&lt;/code&gt; documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Define a global constant, saying that the value is constant and may be compiled into code. If the variable already has a value, and this is not EQL to the new value, the code is not portable (undefined behavior). The third argument is an optional documentation string for the variable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;eql&lt;/code&gt; thing is in the spec, what an implementation should do when
redefining a constant is not defined, so it may vary with your
implementation.&lt;/p&gt;

&lt;p&gt;We invite you to look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://alexandria.common-lisp.dev/draft/alexandria.html#Data-and-Control-Flow&#34;&gt;Alexandria&amp;rsquo;s define-constant&lt;/a&gt;, which has a &lt;code&gt;:test&lt;/code&gt; keyword (but still errors out on redefinition).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md#defconst-symbol-init-optional-docstring&#34;&gt;Serapeum&amp;rsquo;s &lt;code&gt;defconst&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cl:defparameter&lt;/code&gt; ;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;guidelines-and-best-practices&#34;&gt;Guidelines and best practices&lt;/h2&gt;

&lt;p&gt;A few style guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create all your top-level parameters at the top of a file&lt;/li&gt;
&lt;li&gt;define first parameters then variables&lt;/li&gt;
&lt;li&gt;use docstrings&lt;/li&gt;
&lt;li&gt;read your compiler&amp;rsquo;s warnings&lt;/li&gt;
&lt;li&gt;it&amp;rsquo;s better for your functions to accept arguments, rather than to rely on top-level parameters&lt;/li&gt;
&lt;li&gt;your functions shouldn&amp;rsquo;t mutate (modify) a top-level binding. You should create a new data structure instead, and use your function&amp;rsquo;s return value as the parameter to another function, and have data flow from one function to another.&lt;/li&gt;
&lt;li&gt;parameters are best for: a webserver port, a default value… and other user-facing parameters.&lt;/li&gt;
&lt;li&gt;variables are best for long-living and internal variables: caches, DB connections…&lt;/li&gt;
&lt;li&gt;you can forget about defconstant&lt;/li&gt;
&lt;li&gt;when in doubt, use a &lt;code&gt;defparameter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the pattern where a function parameter is by default a global variable is typical and idiomatic:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; from the STR library.
(defvar *whitespaces* (list #\Backspace #\Tab #\Linefeed #\Newline #\Vt #\Page
                            #\Return #\Space #\Rubout
                            ;; edited for brevity
                            ))

(defun trim-left (s &amp;amp;key (char-bag *whitespaces*))
  &amp;quot;Removes all characters in `char-bag` (default: whitespaces) at the beginning of `s`.&amp;quot;
  (when s
   (string-left-trim char-bag s)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the default value can also be a function call:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; from the Lem editor
(defun buffer-modified-p (&amp;amp;optional (buffer (current-buffer)))
  &amp;quot;Return T if &#39;buffer&#39; has been modified, NIL otherwise.&amp;quot;
  (/= 0 (buffer-%modified-p buffer)))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;these let bindings over global variables are idiomatic too: &lt;code&gt;(let ((*name* &amp;quot;other&amp;quot;)) …)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Lisp error handling (advanced): how handler-bind doesn&#39;t unwind the stack</title>
      <link>/blog/lisp-error-handling-how-handler-bind-does-not-unwind-the-stack/</link>
      <pubDate>Tue, 08 Jul 2025 11:45:58 +0200</pubDate>
      
      <guid>/blog/lisp-error-handling-how-handler-bind-does-not-unwind-the-stack/</guid>
      <description>

&lt;p&gt;I updated the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/error_handling.html#absolute-control-over-conditions-and-restarts-handler-bind&#34;&gt;Condition Handling page on the Common Lisp Cookbook&lt;/a&gt; to show what it means that &lt;code&gt;handler-bind&lt;/code&gt; &amp;ldquo;doesn&amp;rsquo;t unwind the stack&amp;rdquo;, along with a couple real-world use cases.&lt;/p&gt;

&lt;p&gt;This time I must thank Ari. I originally wrote the page (with
contributions from jsjolen, rprimus and phoe), starting from Timmy
Jose &amp;ldquo;z0ltan&amp;rdquo;&amp;rsquo;s article (linked in the introduction) and the books I
had at my disposal. These don&amp;rsquo;t show &lt;code&gt;handler-bind&lt;/code&gt;&amp;rsquo;s power and
use-cases like this, focusing on restarts (which this page certainly
could explain better, it shows they aren&amp;rsquo;t part of my daily
toolbelt). So I learned about the real goodness by chance while
reading @shinmera&amp;rsquo;s code and, shame on me, I didn&amp;rsquo;t update the
Cookbook. My video course has been well and complete for years though
;) I needed fresh eyes and that happened with Ari. He asked if I
offered 1-1 video &lt;em&gt;lisp mentoring&lt;/em&gt;. I didn&amp;rsquo;t, but &lt;em&gt;now I do!&lt;/em&gt;. So, as
we talked about a million things (lisp and software development in
general) and eventually worked on condition handling, I realized this
page was lacking, and I took an extra 1h 40min to update it,
&amp;ldquo;backporting&amp;rdquo; content from my video course.&lt;/p&gt;

&lt;p&gt;These days my attention is more turned towards my &lt;a href=&#34;https://web-apps-in-lisp.github.io/&#34;&gt;tutorials for web
development in Common Lisp&lt;/a&gt;, my
CL projects and libraries, and less to the Cookbook alone like before,
but for this edit to the Cookbook 2 things were new and important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I had &lt;em&gt;fresh eyes again&lt;/em&gt;, thanks to the lisp mentoring&lt;/li&gt;
&lt;li&gt;I had an &lt;em&gt;extra motivation&lt;/em&gt; to do the edit in the context of the 1-1
session: I felt it&amp;rsquo;s part of the job. By the way, we settled on
40USD an hour and I have a couple more slots available in the week
;) Please contact me by email (@ vindarel (. mailz org)) Thanks! [/end of
self plug].&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what is this all about? &lt;code&gt;handler-bind&lt;/code&gt;, unlike &lt;code&gt;handler-case&lt;/code&gt;,
doesn&amp;rsquo;t unwind the stack: it shows us the full backtrace and gives us
absolute control over conditions and restarts.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s particularly necessary if you want to print a meaningful
backtrace. We&amp;rsquo;ll give another development tip, where you can decide to either
print a backtrace (production mode) or accept to be dropped into the
debugger (&lt;code&gt;invoke-debugger&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Feel free to leave feedback, in the comments or in the Cookbook issues or &lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/pull/588&#34;&gt;PR&lt;/a&gt;.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#absolute-control-over-conditions-and-restarts-handler-bind&#34;&gt;Absolute control over conditions and restarts: &lt;code&gt;handler-bind&lt;/code&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#handler-bind-doesnt-unwind-the-stack&#34;&gt;handler-bind doesn&amp;rsquo;t unwind the stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#when-to-use-which&#34;&gt;When to use which?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#invoking-the-debugger-manually&#34;&gt;Invoking the debugger manually&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-words&#34;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;absolute-control-over-conditions-and-restarts-handler-bind&#34;&gt;Absolute control over conditions and restarts: &lt;code&gt;handler-bind&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://cl-community-spec.github.io/pages/handler_002dbind.html&#34;&gt;handler-bind&lt;/a&gt; is what to use when we need absolute
control over what happens when a condition is signaled. It doesn&amp;rsquo;t
unwind the stack, which we illustrate in the next section. It allows
us to use the debugger and restarts, either interactively or
programmatically.&lt;/p&gt;

&lt;p&gt;Its general form is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-bind ((a-condition #&#39;function-to-handle-it)
               (another-one #&#39;another-function))
    (code that can...)
    (...error out…)
    (... with an implicit PROGN))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun handler-bind-example ()
  (handler-bind
        ((error (lambda (c)
                  (format t &amp;quot;we handle this condition: ~a&amp;quot; c)
                  ;; Try without this return-from: the error bubbles up
                  ;; up to the interactive debugger.
                  (return-from handler-bind-example))))
      (format t &amp;quot;starting example…~&amp;amp;&amp;quot;)
      (error &amp;quot;oh no&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&amp;rsquo;ll notice that its syntax is &amp;ldquo;in reverse&amp;rdquo; compared to
&lt;code&gt;handler-case&lt;/code&gt;: we have the bindings first, the forms (in an implicit
progn) next.&lt;/p&gt;

&lt;p&gt;If the handler returns normally (it declines to handle the condition),
the condition continues to bubble up, searching for another handler,
and it will find the interactive debugger.&lt;/p&gt;

&lt;p&gt;This is another difference from &lt;code&gt;handler-case&lt;/code&gt;: if our handler
function didn&amp;rsquo;t explicitely return from its calling function with
&lt;code&gt;return-from handler-bind-example&lt;/code&gt;, the error would continue to bubble
up, and we would get the interactive debugger.&lt;/p&gt;

&lt;p&gt;This behaviour is particularly useful when your program signaled a
simple condition. A simple condition isn&amp;rsquo;t an error (see our
&amp;ldquo;conditions hierarchy&amp;rdquo; below) so it won&amp;rsquo;t trigger the debugger. You
can do something to handle the condition (it&amp;rsquo;s a signal for something
occuring in your application), and let the program continue.&lt;/p&gt;

&lt;p&gt;If some library doesn&amp;rsquo;t handle all conditions and lets some bubble out
to us, we can see the restarts (established by &lt;code&gt;restart-case&lt;/code&gt;)
anywhere deep in the stack, including restarts established by other
libraries that this library called.&lt;/p&gt;

&lt;h3 id=&#34;handler-bind-doesn-t-unwind-the-stack&#34;&gt;handler-bind doesn&amp;rsquo;t unwind the stack&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;handler-bind&lt;/code&gt;, we can see the full stack trace, with every
frame that was called. Once we use &lt;code&gt;handler-case&lt;/code&gt;, we &amp;ldquo;forget&amp;rdquo; many
steps of our program&amp;rsquo;s execution until the condition is handled: the
call stack is unwound (or &amp;ldquo;untangled&amp;rdquo;, &amp;ldquo;shortened&amp;rdquo;). &lt;code&gt;handler-bind&lt;/code&gt; does not rewind the
stack. Let&amp;rsquo;s illustrate this.&lt;/p&gt;

&lt;p&gt;For the sake of our demonstration, we will use the library
&lt;code&gt;trivial-backtrace&lt;/code&gt;, which you can install with Quicklisp:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload &amp;quot;trivial-backtrace&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is a wrapper around the implementations&amp;rsquo; primitives such as &lt;code&gt;sb-debug:print-backtrace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Consider the following code: our &lt;code&gt;main&lt;/code&gt; function calls a chain of
functions which ultimately fail by signaling an &lt;code&gt;error&lt;/code&gt;. We handle the
error in the main function with &lt;code&gt;hander-case&lt;/code&gt; and print the backtrace.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun f0 ()
  (error &amp;quot;oh no&amp;quot;))

(defun f1 ()
  (f0))

(defun f2 ()
  (f1))

(defun main ()
  (handler-case (f2)
    (error (c)
      (format t &amp;quot;in main, we handle: ~a&amp;quot; c)
      (trivial-backtrace:print-backtrace c))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the backtrace (only the first frames):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CL-REPL&amp;gt; (main)
in main, we handle: oh no
Date/time: 2025-07-04-11:25!
An unhandled error condition has been signalled: oh no

Backtrace for: #&amp;lt;SB-THREAD:THREAD &amp;quot;repl-thread&amp;quot; RUNNING {1008695453}&amp;gt;
0: […]
1: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE … )
2: (MAIN)
[…]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far so good. It is &lt;code&gt;trivial-backtrace&lt;/code&gt; that prints the &amp;ldquo;Date/time&amp;rdquo; and the message &amp;ldquo;An unhandled error condition…&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Now compare the stacktrace when we use &lt;code&gt;handler-bind&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun main-no-stack-unwinding ()
  (handler-bind
      ((error (lambda (c)
                (format t &amp;quot;in main, we handle: ~a&amp;quot; c)
                (trivial-backtrace:print-backtrace c)
                (return-from main-no-stack-unwinding))))
    (f2)))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;CL-REPL&amp;gt; (main-no-stack-unwinding)
in main, we handle: oh no
Date/time: 2025-07-04-11:32!
An unhandled error condition has been signalled: oh no

Backtrace for: #&amp;lt;SB-THREAD:THREAD &amp;quot;repl-thread&amp;quot; RUNNING {1008695453}&amp;gt;
0: …
1: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE …)
2: …
3: …
4: (ERROR &amp;quot;oh no&amp;quot;)
5: (F0)
6: (F1)
7: (MAIN-NO-STACK-UNWINDING)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s right: you can see all the call stack: from the main function
to the error through &lt;code&gt;f1&lt;/code&gt; and &lt;code&gt;f0&lt;/code&gt;. These two intermediate functions
were not present in the backtrace when we used &lt;code&gt;handler-case&lt;/code&gt; because,
as the error was signaled and bubbled up in the call stack, the stack
was &lt;em&gt;unwound&lt;/em&gt;, and we lost information.&lt;/p&gt;

&lt;h3 id=&#34;when-to-use-which&#34;&gt;When to use which?&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;handler-case&lt;/code&gt; is enough when you expect a situation to fail. For
example, in the context of an HTTP request, it is a common to anticipate a 400-ish error:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; using the dexador library.
(handler-case (dex:get &amp;quot;http://bad-url.lisp&amp;quot;)
  (dex:http-request-failed (e)
    ;; For 4xx or 5xx HTTP errors: it&#39;s OK, this can happen.
    (format *error-output* &amp;quot;The server returned ~D&amp;quot; (dex:response-status e))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In other exceptional situations, we&amp;rsquo;ll surely want &lt;code&gt;handler-bind&lt;/code&gt;. For
example, when we want to handle what went wrong and we want to print a
backtrace, or if we want to invoke the debugger manually (see below)
and see exactly what happened.&lt;/p&gt;

&lt;h2 id=&#34;invoking-the-debugger-manually&#34;&gt;Invoking the debugger manually&lt;/h2&gt;

&lt;p&gt;Suppose you handle a condition with &lt;code&gt;handler-bind&lt;/code&gt;, and your condition
object is bound to the &lt;code&gt;c&lt;/code&gt; variable (as in our examples
above). Suppose a parameter of yours, say &lt;code&gt;*devel-mode*&lt;/code&gt;, tells you
are not in production. It may be handy to fire the debugger on the
given condition. Use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(invoke-debugger c)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In production, you can print the backtrace instead and have an error
reporting tool like Sentry notify you.&lt;/p&gt;

&lt;h1 id=&#34;closing-words&#34;&gt;Closing words&lt;/h1&gt;

&lt;p&gt;This is yet another CL feature I wish I had known earlier and learned
by chance. I hope you learned a thing or two!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hacker News now runs on top of Common Lisp</title>
      <link>/blog/hacker-news-now-runs-on-top-of-common-lisp/</link>
      <pubDate>Mon, 26 May 2025 17:46:52 +0200</pubDate>
      
      <guid>/blog/hacker-news-now-runs-on-top-of-common-lisp/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com&#34;&gt;Hacker News&lt;/a&gt; was written in the
&lt;a href=&#34;http://arclanguage.org/&#34;&gt;Arc&lt;/a&gt; lisp dialect, a dialect created by Paul
Graham. Arc was implemented on top of Racket, but that has now
changed. HN runs on top of SBCL since (at least) September of 2024.&lt;/p&gt;

&lt;p&gt;But why? For performance reasons.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I recently noticed that Hacker News no longer uses paging for long
threads. In the past, when a discussion grew large, we had to click
&amp;ldquo;More&amp;rdquo; to load the next page of comments, and dang would
occasionally post helpful tips to remind us about this feature.
Was there an announcement regarding this change? Has anyone else still seen paging recently? I&amp;rsquo;d love to know more details—especially the technical aspects or considerations that went into the decision.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s because Clarc is finally out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=41679215&#34;&gt;dang, Sept. 2024&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[Clarc] is much faster and also will easily let HN run on multiple cores. It&amp;rsquo;s been in the works for years, mainly because I rarely find time to work on it, but it&amp;rsquo;s all pretty close to done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=32597291&#34;&gt;dang, 2022&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it&amp;rsquo;s done:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;there&amp;rsquo;s now an Arc-to-JS called Lilt, and an Arc-to-Common Lisp called Clarc. In order to make those easier to develop, we reworked the lower depths of the existing Arc implementation to build Arc up in stages. The bottom one is called arc0, then arc1 is written in arc0, and arc2 in arc1. The one at the top (arc2, I think) is full Arc. This isn&amp;rsquo;t novel, but it makes reimplementation easier since you pack as much as possible in the later stages, and only arc0 needs to be written in the underlying system (Racket, JS, or CL).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=21550123&#34;&gt;dang, 2019&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But Clarc&amp;rsquo;s code isn&amp;rsquo;t released, although it could be done:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;open-sourcing the Arc implementation (i.e. Clarc) would be much
easier [than the HN site]. The way to do it would be to port the
original Arc release (&lt;a href=&#34;http://arclanguage.org/&#34;&gt;http://arclanguage.org/&lt;/a&gt;) to Clarc. It includes
a sample application which is an early version of HN, scrubbed of
anything HN- or YC-specific.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=44099560&#34;&gt;dang, day of this post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Releasing the new HN code base however wouldn&amp;rsquo;t work:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Much of the HN codebase consists of anti-abuse measures that would stop working if people knew about them. Unfortunately.
separating out the secret parts would by now be a lot of work. The time to do it will be if and when we eventually release the alternative Arc implementations we&amp;rsquo;ve been working on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=21546438&#34;&gt;https://news.ycombinator.com/item?id=21546438&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;Congrats for the successful &amp;ldquo;splash-free&amp;rdquo; transition though.&lt;/p&gt;

&lt;hr /&gt;

&lt;ul&gt;
&lt;li&gt;edit 10PM UTC+2: added a quote to clarify about open-sourcing the HN code (&amp;ldquo;wouldn&amp;rsquo;t work&amp;rdquo;) VS Clarc itself (&amp;ldquo;much easier&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;edit May, 27th: reworded &amp;ldquo;since a few months&amp;rdquo; to mention a date.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>These years in Common Lisp: 2023-2024 in review</title>
      <link>/blog/these-years-in-common-lisp-2023-2024-in-review/</link>
      <pubDate>Mon, 17 Feb 2025 19:06:46 +0200</pubDate>
      
      <guid>/blog/these-years-in-common-lisp-2023-2024-in-review/</guid>
      <description>

&lt;!-- libraries [Project Mage: A Structural UI platform built in Common Lisp](https://project-mage.org/Campaign) --&gt;

&lt;p&gt;This is a personal pick of the most interesting projects, tools,
libraries and articles that popped-up in Common Lisp land in the last
two years.&lt;/p&gt;

&lt;p&gt;Newcomers might not realize how the Common Lisp ecosystem, though
stable in many ways, actually evolves, sharpens, tries new solutions,
proposes new tools, ships new libraries, revives projects. And
everyone might enjoy a refresher.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s my &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-years-in-common-lisp-2022-in-review/&#34;&gt;previous overview for 2022&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The same warnings hold: I picked the most important links, in my
view, but this list is by no means a compilation of &lt;em&gt;all&lt;/em&gt; new CL
projects or articles published on the topic. Look for yourself on Reddit,
Quicklisp releases, GitHub, and use your favourite search engine.&lt;/p&gt;

&lt;p&gt;There are too many great news and achievements to pick 3. I love
what&amp;rsquo;s happening around &lt;strong&gt;SBCL&lt;/strong&gt; (and ECL, and Clozure&amp;rsquo;s revival), I
love everything that got included into &lt;strong&gt;Lem&lt;/strong&gt; and the work on all
other editors, I love the &lt;strong&gt;webviews&lt;/strong&gt; and I love the &lt;strong&gt;scripting&lt;/strong&gt;
tools that are emerging. What are your top picks?&lt;/p&gt;

&lt;p&gt;OK, there&amp;rsquo;s a news I want to put at the forefront: &lt;strong&gt;HackerNews now runs on top of SBCL&lt;/strong&gt; ;)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;If you are discovering the ecosystem, my recommendaton is to not miss
these two resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome-cl&lt;/a&gt; - a curated list of libraries (there might be more than you think)

&lt;ul&gt;
&lt;li&gt;if you are looking for a list of recommended libraries on each topic, look here.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;the CL Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let&amp;rsquo;s dive in and thanks to everyone involved.&lt;/p&gt;



&lt;a href=&#34;https://opusmodus.com/&#34;&gt;
&lt;img src=&#34;https://i.redd.it/ffb8gu6zobta1.png&#34; style=&#34;max-width: 100%;&#34; alt=&#34;The OpusModus music composition software.&#34; title=&#34;The OpusModus music composition software version 3, with a Windows version. A LispWorks product, not open-source, with demo videos below.&#34;/&gt;
&lt;/a&gt;



&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#community&#34;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#documentation&#34;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#implementations&#34;&gt;Implementations&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#sbcl&#34;&gt;SBCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#abcl&#34;&gt;ABCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ccl&#34;&gt;CCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#allegro&#34;&gt;Allegro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#lispworks&#34;&gt;LispWorks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ecl&#34;&gt;ECL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#clasp&#34;&gt;CLASP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sicl---the-new-portable-and-modular-implementation&#34;&gt;SICL - the new, portable and modular implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#new-implementations&#34;&gt;New implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#historical-medley-interlisp&#34;&gt;Historical: Medley Interlisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#companies-and-jobs&#34;&gt;Companies and jobs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#projects&#34;&gt;Projects&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#editors&#34;&gt;Editors&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#about-emacs&#34;&gt;About Emacs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#about-vscode&#34;&gt;About VSCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#about-lem-and-rooms-pair-programming-environment&#34;&gt;About Lem and Rooms pair programming environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#about-lispworks&#34;&gt;About LispWorks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#about-the-jetbrains-plugin&#34;&gt;About the Jetbrains plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#about-jupyter&#34;&gt;About Jupyter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-tools&#34;&gt;Other tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#coalton&#34;&gt;Coalton&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#package-managers&#34;&gt;Package managers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gamedev&#34;&gt;Gamedev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gui&#34;&gt;GUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#web&#34;&gt;Web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nyxt-40-pre-realease---now-on-electron&#34;&gt;Nyxt 4.0 pre-realease - now on Electron&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#more-libraries&#34;&gt;More libraries&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#scripting&#34;&gt;Scripting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#software-releases&#34;&gt;Software releases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-articles&#34;&gt;Other articles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#videos&#34;&gt;Videos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;community&#34;&gt;Community&lt;/h1&gt;

&lt;p&gt;We could start with some reddit stats: &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1hr2omd/2025_a_new_year_for_an_old_programming_language/&#34;&gt;2025 - a New Year for an old programming language!&lt;/a&gt; (numbers are up).&lt;/p&gt;

&lt;p&gt;The ELS team kept organizing the conference. We have a date and place for 2025: &lt;a href=&#34;https://www.european-lisp-symposium.org/2025/index.html&#34;&gt;European Lisp Symposium 2025 in Zürich, May &lt;sup&gt;19&lt;/sup&gt;&amp;frasl;&lt;sub&gt;20&lt;/sub&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We saw new and regular &lt;a href=&#34;https://lisp.ie/&#34;&gt;Lisp Ireland&lt;/a&gt; &lt;a href=&#34;https://stripe.events/lispirelandatstripe&#34;&gt;meetups&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s one of their videos: &lt;a href=&#34;https://www.youtube.com/watch?v=iFEb9p54x_Q&#34;&gt;Lisp Ireland, February 2024 Meetup - Lisp &amp;amp; Hardware Verification with ACL2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;@djha-skin ran a survey, which is not an established practice in the community, and analysed the results: &lt;a href=&#34;https://blog.djhaskin.com/blog/common-lisp-community-survey-2024-results/&#34;&gt;Common Lisp Community Survey 2024 Results &lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;@shinmera (Yukari), the author of many useful libraries and an active member of the ELS, and even the host of the next one, &lt;a href=&#34;https://www.patreon.com/Shinmera&#34;&gt;opened a Patreon. &amp;ldquo;If you&amp;rsquo;d like to help me continue my full-time open source Lisp work, please consider supporting me.&amp;rdquo;&lt;/a&gt;. Sponsoring Yukari is money well spent. She is &lt;a href=&#34;https://github.com/sponsors/Shinmera&#34;&gt;on GH sponsors&lt;/a&gt; and &lt;a href=&#34;https://ko-fi.com/shinmera&#34;&gt;ko-fi&lt;/a&gt; too.&lt;/p&gt;

&lt;p&gt;The community is on reddit, &lt;a href=&#34;https://discord.gg/hhk46CE&#34;&gt;Discord&lt;/a&gt;, Mastodon, LinkedIn… and also on &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1iazlrr/lisp_xmpp_channel/&#34;&gt;XMPP&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;p&gt;The &lt;strong&gt;CL Cookbook&lt;/strong&gt; is a collaborative resource with new contributors each year: &lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/releases/tag/2025-01-09&#34;&gt;new Cookbook EPUB and PDF release: 2025-01&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We got a great contribution: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/dynamic-libraries.html&#34;&gt;Cookbook: Building Dynamic Libraries with SBCL-Librarian · by em7&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PAIP&lt;/strong&gt; is a classic, now available on the web: &lt;a href=&#34;https://norvig.github.io/paip-lisp/#/&#34;&gt;Peter Norvig: Paradigms of Artificial Intelligence Programming, Case Studies in Common Lisp (web version)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://web-apps-in-lisp.github.io/index.html&#34;&gt;New resource: &lt;strong&gt;Web Apps in Lisp: Know-how&lt;/strong&gt;&lt;/a&gt;: I wanted a resource specialized for web development in Common Lisp. I mean to continuously extend it from now on.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll include a couple general videos in this section. More videos and more documentation improvements are to be found in their respective sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FreeCodeCamp&lt;/strong&gt; released an extensive Common Lisp course on Youtube: &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1i1e766/lisp_programming_language_full_course_for/&#34;&gt;Lisp Programming Language – Full Course for Beginners - freeCodeCamp.org - Youtube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;David Botton of CLOG fame released more beginner material, among which &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/196lain/common_lisp_the_tutorial_fast_fun_and_practical/&#34;&gt;Common Lisp - The Tutorial - Fast, Fun and Practical (with CLOG)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I carry on the work on my &lt;strong&gt;Common Lisp course&lt;/strong&gt; in videos, on the Udemy platform. Lately, I worked on a &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/clos-tutorial-in-9-videos-1h22min--read-the-sources-of-hunchentoot-and-kandria/&#34;&gt;CLOS tutorial: I published 9 videos (1h 22min) on my course. You&amp;rsquo;ll know enough to read the sources of Hunchentoot or the Kandria game 🎥&lt;/a&gt; &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1hiraze/clos_tutorial_i_published_9_videos_1h_22min_on_my/&#34;&gt;comments&lt;/a&gt;. The course is comprised of more than 7 hours of short videos, with a code first approach, divided in 9 chapters. We see some basics but we quickly dive into more advanced Common Lisp topics. You can learn more about it &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;here on GitHub&lt;/a&gt;. Students can send me an email for a free link.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the feedback of redditors:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I can vouch for the Udemy course. From the very first lesson, just firing up the REPL and Emacs/SLIME I was taught something new. It&amp;rsquo;s a great course.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;fuzzmonkey35, January 2025 (reddit)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is an amazing tutorial. What is really strange is I thought CLOS was complicated. I guess it can be but Vincent is amazing at explaining everything and demystifying it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;intergallactic_llama, January 2025 (reddit)&lt;/p&gt;

&lt;p&gt;;)&lt;/p&gt;

&lt;h1 id=&#34;implementations&#34;&gt;Implementations&lt;/h1&gt;

&lt;p&gt;Great times for Common Lisp implementations.&lt;/p&gt;

&lt;h2 id=&#34;sbcl&#34;&gt;SBCL&lt;/h2&gt;

&lt;p&gt;SBCL &lt;a href=&#34;https://www.sbcl.org/news.html&#34;&gt;ships monthly releases&lt;/a&gt;. You really should look at and appreciate all the activity and the continous improvements.&lt;/p&gt;

&lt;p&gt;One noticeable addition: its &lt;strong&gt;new garbage collector&lt;/strong&gt;. &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/15nmv0h/sbcl_merge_of_markregion_gc/&#34;&gt;SBCL: merge of the mark-region GC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;More improvements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;the mark-region parallel garbage collector can be enabled on arm64. (Thanks to Hayley Patton)&amp;rdquo;,&lt;/li&gt;
&lt;li&gt;new contrib module sb-perf, &amp;ldquo;a performance-analysing tool for Linux. (thanks to Luke Gorrie and Philipp Marek)&amp;rdquo;&lt;/li&gt;
&lt;li&gt;support for cross-compiling the system to Android has been added (thanks to Gleefre)&lt;/li&gt;
&lt;li&gt;&amp;ldquo;support for memory allocation arenas is now available on the arm64 platform.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;haiku support

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://discuss.haiku-os.org/t/make-ansi-common-lisp-available-on-haiku-again/15780&#34;&gt;Porting Common Lisp to Haiku OS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;sb-simd improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More good stuff with SBCL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://reader.tymoon.eu/article/437&#34;&gt;Porting SBCL to the &lt;strong&gt;Nintendo Switch&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/12pxuja/sbcl_as_part_of_an_android_application/&#34;&gt;SBCL as part of an &lt;strong&gt;Android&lt;/strong&gt; application!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/13ajpp0/simple_repl_app_sbcl_android_wip/&#34;&gt;Simple REPL App. (SBCL, Android - WIP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/tree-shaker&#34;&gt;40ants/tree-shaker: experimental tree shaker for SBCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://community.chocolatey.org/packages/sbcl&#34;&gt;SBCL can now be installed on Windows via &lt;strong&gt;Chocolatey&lt;/strong&gt; (unofficial)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/olnw/sbcl-builds&#34;&gt;sbcl-builds: &lt;strong&gt;Nightly builds of SBCL&lt;/strong&gt; for Windows using MSYS2 UCRT64.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.cddr.org/posts/2023-02-20-distributing-binaries-cl-ffi/&#34;&gt;sbcl-goodies: distributing binaries with Common Lisp and foreign libraries. libssl, libcrypto and libfixposix are statically baked in.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;!-- &lt;figure&gt; --&gt;
  &lt;a href=&#34;https://reader.tymoon.eu/article/437&#34;&gt;
    &lt;img src=&#34;https://filebox.tymoon.eu//file/TWpjNU5nPT0=&#34; style=&#34;max-width: 50%; margin: 2em;&#34; alt=&#34;SBCL on the Nintendo Switch&#34; title=&#34;SBCL with the Trial game engine on the Nintendo Switch.&#34;/&gt;
 &lt;/a&gt;
    &lt;!-- &lt;figcaption&gt;Porting SBCL to the Nintendo Switch&lt;/figcaption&gt; --&gt;
&lt;!-- &lt;figure&gt; --&gt;



&lt;p&gt;There are open bounties to improve SBCL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1hncabr/2000_usd_bounty_to_see_byvalue_struct_passing/&#34;&gt;&lt;strong&gt;$2000 USD bounty&lt;/strong&gt; to see by-value struct passing implemented in SBCL&amp;rsquo;s native FFI.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;it may be more than $2000 USD now.&lt;/li&gt;
&lt;li&gt;You wouldn&amp;rsquo;t start from zero, there is existing work. See the thread.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;another $700+ bounty to add &lt;strong&gt;coroutines&lt;/strong&gt; in SBCL

&lt;ul&gt;
&lt;li&gt;same link. No official bounty page yet, I may work on it.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;abcl&#34;&gt;ABCL&lt;/h2&gt;

&lt;p&gt;New release: &lt;a href=&#34;https://abcl-dev.blogspot.com/2023/02/abcl-191-never-use-dot-oh.html&#34;&gt;ABCL 1.9.1 &amp;ldquo;never use a dot oh&amp;rdquo;: CFFI compatibilities, Java virtual threads, ASDF 3.3.6, fixed loading of Fricas0 and Maxima…&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New release &lt;a href=&#34;https://abcl.org/release-notes-1.9.2.shtml&#34;&gt;ABCL 1.9.2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;New tool: &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1eqvwnb/announcing_the_first_release_of/&#34;&gt;Announcing the First Release of abcl-memory-compiler - Now Available!&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;ccl&#34;&gt;CCL&lt;/h2&gt;

&lt;p&gt;Clozure was a bit active, but rather dormant.&lt;/p&gt;

&lt;p&gt;Great news: &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1c0kq27/clozure_is_back/&#34;&gt;&lt;strong&gt;Clozure is back&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Clozure/ccl/releases/tag/v1.13&#34;&gt;Clozure CL 1.13 released&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;allegro&#34;&gt;Allegro&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://franz.com/products/allegro-common-lisp/&#34;&gt;Allegro Common Lisp 11.0 from Franz Inc.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;lispworks&#34;&gt;LispWorks&lt;/h2&gt;

&lt;p&gt;I didn&amp;rsquo;t spot a patch release (they had a major release in 2022), so let&amp;rsquo;s link to a discussion: &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/11979q4/common_lisp_implementations_in_2023/&#34;&gt;is LispWorks worth it?&lt;/a&gt; you might learn some things about LW&amp;rsquo;s feature set.&lt;/p&gt;

&lt;h2 id=&#34;ecl&#34;&gt;ECL&lt;/h2&gt;

&lt;p&gt;Embeddable, targetting WASM… is it the future?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ecl.common-lisp.dev/posts/ECL-24510-release.html&#34;&gt;ECL 24.5.10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mailman3.common-lisp.net/hyperkitty/list/ecl-devel@common-lisp.net/thread/T64S5EMVV6WHDPKWZ3AQHEPO3EQE2K5M/&#34;&gt;ECL runs Maxima in a browser with WASM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;clasp&#34;&gt;CLASP&lt;/h2&gt;

&lt;p&gt;CLASP targets C++ on LLVM.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/clasp-developers/clasp/releases/tag/2.5.0&#34;&gt;Release: Clasp v2.5.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They realeased &lt;a href=&#34;https://github.com/clasp-developers/clasp/releases/&#34;&gt;Clasp v2.7.0&lt;/a&gt; in January, 2025.&lt;/p&gt;

&lt;p&gt;For context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=tQgkvghzW0M&#34;&gt;Christian Schafmeister talk - brief update about his &amp;ldquo;molecular lego&amp;rdquo; supported by his Lisp compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s less funding than in the 80s for Common Lisp, but still funding: &amp;ldquo;CLASP was supported by The Defense Threat Reduction Agency, The National Institutes of Health, The National Science Foundation&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;sicl-the-new-portable-and-modular-implementation&#34;&gt;SICL - the new, portable and modular implementation&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/robert-strandh/SICL&#34;&gt;SICL&lt;/a&gt; implementation is very active.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SICL is a new implementation of Common Lisp. It is intentionally divided into many implementation-independent modules that are written in a totally or near-totally portable way, so as to allow other implementations to incorporate these modules from SICL, rather than having to maintain their own, perhaps implementation-specific versions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;SICL&amp;rsquo;s components are used, for example, in the CLASP implementation.&lt;/p&gt;

&lt;p&gt;Related, the &lt;a href=&#34;https://github.com/robert-strandh/Second-Climacs&#34;&gt;second-climacs&lt;/a&gt; editor shows good activity too. Watch &lt;a href=&#34;https://scymtym.github.io/content/second-climacs-9.mp4&#34;&gt;this demo&lt;/a&gt;, showing on-the-fly code parsing and feedback, it looks pretty cool. Here too, each achievement is extracted into its own component. So the second-climacs&amp;rsquo; codebase actualy shrinks with time.&lt;/p&gt;

&lt;p&gt;If you want to hack on CL, those are good places.&lt;/p&gt;

&lt;h2 id=&#34;new-implementations&#34;&gt;New implementations&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1gr3z94/a_common_lisp_implementation_in_development/&#34;&gt;A Common Lisp implementation in development in C89 (no compiler so far)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;called ALisp, &amp;ldquo;breakpoints and stepping work quite well&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/gsou/LCL&#34;&gt;gsou/LCL: Lua Common Lisp. An implementation of Common Lisp targeting Lua.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;historical-medley-interlisp&#34;&gt;Historical: Medley Interlisp&lt;/h2&gt;

&lt;p&gt;We can run the Medley Interlisp Lisp machine in a browser O_o The work achieved by this group is phenomenal, look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://interlisp.org/project/status/2023medleyannualreport/&#34;&gt;2023 Medley Interlisp Project Annual Report&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://interlisp.org/project/status/2023medleyannualreport/&#34;&gt;2024 Medley Interlisp Project Annual Report&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I suggest to follow &lt;code&gt;@interlisp@fosstodon.org&lt;/code&gt; on Mastodon.&lt;/p&gt;

&lt;h1 id=&#34;companies-and-jobs&#34;&gt;Companies and jobs&lt;/h1&gt;

&lt;p&gt;Yes, some companies still choose Common Lisp today, and some hire with a public job posting.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s of course the visible top of the iceberg. If you dream of a Lisp
job, I suggest to be active and make yourself visible, you might be
contacted by someone without a proper job announce. This could be for
an open-source project with funding (happened to me), for a
university, etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a new product: &lt;a href=&#34;https://graphmetrix.com/Aconex&#34;&gt;Oracle Aconex Accelerator · &amp;ldquo;Over 5 years of development and scaling, the entire Conceptual AI linked data platform is built on Common Lisp (SBCL).&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;experience report: &lt;a href=&#34;https://blog.funcall.org/lisp%20psychoacoustics/2024/05/01/worlds-loudest-lisp-program/&#34;&gt;the World&amp;rsquo;s Loudest Lisp Program to the Rescue, by Eugene Zaikonnikov &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: &lt;a href=&#34;https://nofluffjobs.com/job/common-lisp-developer-keepit-krakow&#34;&gt;Common Lisp Developer Job | Backend | Keepit | Kraków&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: (same company, later) &lt;a href=&#34;https://careers.keepit.com/jobs/4747213-common-lisp-developer&#34;&gt;Common Lisp Developer job offer at Keepit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/11s8rli/freelance_job_posting_at_upwork_for_a_common_lisp/&#34;&gt;Freelance job posting at Upwork for a Common Lisp Developer/Engineer.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: &lt;a href=&#34;https://tritonsystems.applicantpro.com/jobs/3610597&#34;&gt;Lisp job: Cognitive Software Engineer - Chelmsford, MA, at Triton Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: &lt;a href=&#34;https://shirakumo.org/jobs&#34;&gt;implement the &amp;ldquo;Convex Hull Covering of Polygonal Scenes&amp;rdquo; paper.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: &lt;a href=&#34;https://careers.dxc.com/global/en/job/51516470/Senior-Lisp-Developer-m-f-d-100-remote&#34;&gt;Senior Lisp Developer (m/f/d), Software &amp;amp; Applications at DXC Technology, work on SARA (SuperAgent Robotic Application), an automation tool designed to streamline complex and repetitive business processes for major airlines.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;job: &lt;a href=&#34;https://jobs.3e.eu/en/vacature/93847/common-lisp-developer/&#34;&gt;senior Common Lisp Developer | 3E, Brussels&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We knew these companies since &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;awesome-lisp-companies&lt;/a&gt; -it&amp;rsquo;s only a list of companies we know about, nothing offical. Additions welcome.&lt;/p&gt;

&lt;p&gt;Discussions on the topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1g9w4cp/anyone_using_common_lisp_for_freelance_work/&#34;&gt;Anyone using Common Lisp for freelance work?&lt;/a&gt; where we learn about cool websites made in CL and cool experience reports.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/running-my-4th-lisp-script-in-production/&#34;&gt;Running my 4th Common Lisp script in production© - you can do it too&lt;/a&gt; aka &amp;ldquo;you don&amp;rsquo;t need crazily difficult needs to make yourself a favour and use CL instead of Python in your projects&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;h2 id=&#34;editors&#34;&gt;Editors&lt;/h2&gt;

&lt;p&gt;Please check out &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/editor-support.html&#34;&gt;the Cookbook: editors&lt;/a&gt; for a list of good editors for Common Lisp. You migth be surprised.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s highlight a new editor in town: &lt;a href=&#34;https://github.com/neomacs-project/neomacs&#34;&gt;Neomacs: Structural Lisp IDE/computing environment &lt;/a&gt;. Mariano integrated it in his moldable web desktop: &lt;a href=&#34;https://github.com/neomacs-project/neomacs/discussions/95&#34;&gt;Integrating Neomacs into my CLOG-powered desktop&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;about-emacs&#34;&gt;About Emacs&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/slime/slime/releases/tag/v2.30&#34;&gt;slime 2.30 · Better I/O performance, macroexpand for macrolet (and more)&lt;/a&gt;- &lt;a href=&#34;https://www.n16f.net/blog/custom-font-lock-configuration-in-emacs/&#34;&gt;Better Common Lisp highlighting in Emacs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/gabrielshanahan/learning-lisp-making-sense-of-xrefs-in-slime-2b6g&#34;&gt;Learning Lisp - making sense of xrefs in SLIME&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;about-vscode&#34;&gt;About VSCode&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.djhaskin.com/blog/experience-report-using-vs-code-alive-to-write-common-lisp/&#34;&gt;Experience Report using VS Code + Alive to Write Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;about-lem-and-rooms-pair-programming-environment&#34;&gt;About Lem and Rooms pair programming environment&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lem-project/lem/releases/tag/v2.0.0&#34;&gt;Lem 2.0.0 released&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;released in May 2023, this version added the SDL2 frontend, adding mouse support, graphic capabilities, and Windows support.&lt;/li&gt;
&lt;li&gt;it brought the possibility to draw images and shapes at any location on a buffer or window.&lt;/li&gt;
&lt;li&gt;addition of many base16 color themes (180), by @lukpank.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lem-project/lem/releases/tag/v2.1.0&#34;&gt;Lem 2.1.0 released&lt;/a&gt;, with many new contributors. Lem 2.0 definitely caught the eyes of many developers IMO.

&lt;ul&gt;
&lt;li&gt;this is when Lem got its website: &lt;a href=&#34;https://lem-project.github.io/&#34;&gt;https://lem-project.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;@sasanidas worked on supporting other implementations: &amp;ldquo;ECL and CCL should work fairly well&amp;rdquo;, &amp;ldquo;ABCL and Clasp are still work in progress, working but with minor bugs.&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;I added project-aware commands, find-file-recursively&lt;/li&gt;
&lt;li&gt;@cxxxr added (among everything else) great Lisp mode additions (just look at the release notes and the screenshots)&lt;/li&gt;
&lt;li&gt;added a sidebar / filer&lt;/li&gt;
&lt;li&gt;and much more. Just look at the release.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;then came out &lt;a href=&#34;https://github.com/lem-project/lem/releases/tag/v2.2.0&#34;&gt;Lem 2.2.0&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;the release notes are less organized ;)&lt;/li&gt;
&lt;li&gt;added &lt;strong&gt;libvterm&lt;/strong&gt; integration&lt;/li&gt;
&lt;li&gt;this is when I added the interactive git mode.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately these latest releases do not ship a readily usable executable. But the installation recipes have been greatly simplified and use Qlot instead of Roswell. There&amp;rsquo;s a one-liner shell command to install Lem on Unixes.&lt;/p&gt;

&lt;p&gt;Lem&amp;rsquo;s creator &lt;a href=&#34;https://github.com/sponsors/cxxxr&#34;&gt;cxxxr is now on GitHub sponsors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;He is also working on &lt;a href=&#34;https://github.com/rooms-dev/lem-rooms-client&#34;&gt;Rooms&lt;/a&gt;, aka Lem on the cloud: it&amp;rsquo;s a Lem-based &amp;ldquo;&lt;strong&gt;pair programming environment&lt;/strong&gt; where you can share your coding sessions&amp;rdquo;. Only the client is open-source, so far at least.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href=&#34;https://www.youtube.com/watch?v=IMN7feOQOak&#34;&gt;https://www.youtube.com/watch?v=IMN7feOQOak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those are the Lem related articles that popped up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/oh-no-i-started-a-magit-like-plugin-for-the-lem-editor/&#34;&gt;Oh no, I started &lt;strong&gt;a Magit-like plugin for the Lem editor&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lem-project.github.io/modes/dashboard/&#34;&gt;Lem customizable &lt;strong&gt;dashboard&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lem/&#34;&gt;Lem has a subreddit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mastodon.social/@frescosecco/112909105139388650&#34;&gt;&lt;strong&gt;Lem in CLIM&lt;/strong&gt; &amp;ldquo;1.0&amp;rdquo; · now with mouse events and smoother performance. (August 2024)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1cc9yq6/lem_on_the_cloud_powerful_webbased_editor_with/&#34;&gt;Lem on the cloud: Powerful web-based Editor with Collaborative Editing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;img src=&#34;https://lisp-journey.gitlab.io/images/lem-status.png&#34;
  style=&#34;max-width: 100%; margin: 2em;&#34; alt=&#34;Lem&#39;s Legit Git interface.&#34; title=&#34;An interactive, magit-like Git interface into Lem.&#34;&gt;&lt;/img&gt;



&lt;h3 id=&#34;about-lispworks&#34;&gt;About LispWorks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apr3vau/lw-plugins&#34;&gt;LispWorks Plugins by April &amp;amp; May&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1e5lfcg/version_control_for_lispworks/&#34;&gt;Version Control for Lispworks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;about-the-jetbrains-plugin&#34;&gt;About the Jetbrains plugin&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Enerccio/SLT/releases/tag/v0.2.0&#34;&gt;SLT Jetbrains plugin v0.2.0 and 0.2.1 - first version of inspector, macro-expand, basic completion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;about-jupyter&#34;&gt;About Jupyter&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://saturncloud.io/blog/jupyter-and-common-lisp-a-powerful-combination-for-data-science/&#34;&gt;Jupyter and Common Lisp: A Powerful Combination for Data Science&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;other-tools&#34;&gt;Other tools&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/digikar99/cl-repl&#34;&gt;CL-REPL now supports multiline editing&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;it also comes as a ready-to-use binary&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;coalton&#34;&gt;Coalton&lt;/h2&gt;

&lt;p&gt;Coalton is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the implementation of a static type system beyond Haskell 95. Full multiparameter type classes, functional dependencies, some persistent data structures, type-oriented optimization (including specialization and monomorphization). All integrated and native to CL without external tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And used in production for years in the quantum industry. See &lt;a href=&#34;https://github.com/quil-lang/quilc/&#34;&gt;quilc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I found Coalton-related projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/garlic0x1/coalton-threads&#34;&gt;https://github.com/garlic0x1/coalton-threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/garlic0x1/coalton-rope&#34;&gt;https://github.com/garlic0x1/coalton-rope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/jbouwman/coalton-lsp&#34;&gt;https://github.com/jbouwman/coalton-lsp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E. Fukamachi added Coalton support for Lem: &lt;a href=&#34;https://lem-project.github.io/modes/coalton-lang/&#34;&gt;https://lem-project.github.io/modes/coalton-lang/&lt;/a&gt;. This adds completion, syntax highlighting, interactive compilation and more inside &amp;ldquo;coalton-toplevel&amp;rdquo; forms.&lt;/p&gt;

&lt;h2 id=&#34;package-managers&#34;&gt;Package managers&lt;/h2&gt;

&lt;p&gt;Quicklisp had a one year hiatus, because it relies on one man. It
finally got an update after 1 year: &lt;a href=&#34;http://blog.quicklisp.org/2024/10/october-2024-quicklisp-dist-update-now.html&#34;&gt;Quicklisp libraries were updated
2024-10-12&lt;/a&gt;. Despite
a &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/17jukzk/october_2023_quicklisp_dist_update_now_available/?&#34;&gt;call for
collaboration&lt;/a&gt;,
we don&amp;rsquo;t really know how we can help.&lt;/p&gt;

&lt;p&gt;But Quicklisp isn&amp;rsquo;t the only library manager anymore.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/13lxhez/ocicl_an_experimental_modern_quicklisp/&#34;&gt;introducing ocicl: an experimental modern quicklisp alternative built on tools from the world of containers &lt;/a&gt; may 2023

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1g2qbmp/ocicl_no_longer_depends_on_the_external_oras/&#34;&gt;ocicl no longer depends on the external oras binary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1ckqujh/ocicl_a_common_lisp_system_manager_now_with_ai/&#34;&gt;ocicl: now with AI powers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ultralisp/ultralisp/pull/213&#34;&gt;Ultralisp now supports any git repositories as project sources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/qlot/releases/tag/1.4.1&#34;&gt;Qlot 1.4.1 - added script for manual installation without Roswell, &amp;ldquo;qlot install&amp;rdquo; runs in parallel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/qlot?tab=readme-ov-file#repl-experimental&#34;&gt;Qlot 1.5.0 - added a REPL interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fosskers/vend&#34;&gt;introducing vend: just vendor your dependencies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.funcall.org//lisp/2023/10/23/deptree/&#34;&gt;Announcing deptree | list and archive dependency snapshots of (ASDF-defined) projects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;gamedev&#34;&gt;Gamedev&lt;/h2&gt;

&lt;p&gt;The Kandria game was released: &lt;a href=&#34;https://kandria.com/&#34;&gt;https://kandria.com/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://shirakumo.github.io/trial/examples&#34;&gt;Trial game engine documentation website and examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mastodon.tymoon.eu/@shinmera/111464312394127769&#34;&gt;My Lisp physics engine for Trial is finally working! &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are into game dev, this is a paper you cannot miss: &lt;a href=&#34;https://raw.githubusercontent.com/Shinmera/talks/master/els2023-kandria/paper.pdf&#34;&gt;Kandria: experience report&lt;/a&gt;, presented at the ELS 2023.&lt;/p&gt;

&lt;p&gt;Great articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://awkravchuk.itch.io/cl-fast-ecs/devlog/622054/gamedev-in-lisp-part-1-ecs-and-metalinguistic-abstraction&#34;&gt;Gamedev in Lisp. Part 1: ECS and Metalinguistic Abstraction &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/lockie/cl-fast-ecs/-/wikis/tutorial-2&#34;&gt;Gamedev in Lisp. Part 2: Dungeons and Interfaces · Wiki · Andrew Kravchuk / cl-fast-ecs · GitLab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=MsVX_1zg4n4&#34;&gt;Multiplayer game with Common Lisp + SDL2 on WebAssembly (short demo video)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I almost forgot the Lisp Game Jams and the new cool little games. For example: &lt;a href=&#34;https://bohonghuang.itch.io/nano-towers&#34;&gt;Nano Towers&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a simple tower defense game written in Common Lisp with the EON framework based on Raylib, submitted for the Spring Lisp Game Jam 2024.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvMjcyOTE1Mi8xNjI3ODI3NC5wbmc=/347x500/I9n75v.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Links to the jams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://itch.io/jam/autumn-lisp-game-jam-2024&#34;&gt;https://itch.io/jam/autumn-lisp-game-jam-2024&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://itch.io/jam/spring-lisp-game-jam-2023&#34;&gt;https://itch.io/jam/spring-lisp-game-jam-2023&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;gui&#34;&gt;GUI&lt;/h2&gt;

&lt;p&gt;Many solutions exist. Disclaimer: the perfect GUI library doesn&amp;rsquo;t exist. Please see the Cookbook/gui and awesome-cl. Also don&amp;rsquo;t miss the web views available today.&lt;/p&gt;

&lt;p&gt;releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mcclim.common-lisp.dev/posts/McCLIM-098-Yule-release.html&#34;&gt;McCLIM 0.9.8 Yule&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/shirakumo/glfw&#34;&gt;Shirakumo/glfw: An up-to-date Common Lisp bindings library to the most recent GLFW OpenGL context management library &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/13qio8q/nodgui_04_released_multithread_main_loop/&#34;&gt;nodgui 0.4 released - multithread main loop, auto-completion entry, extended text widget, better image support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://emacs.ch/@cage/111856866932486274&#34;&gt;nodgui v0.6.0 - Added an SDL frame as an alternative for TK canvas when fast rendering is needed. Both 2D (pixel based) and a 3D rendering (the latter using openGL) are available.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/nodgui-now-has-a-nice-looking-theme-by-default/&#34;&gt;Pretty GUIs now: nodgui comes with a pre-installed nice looking theme&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, we might not highlight the work achieved on existing
libraries that didn&amp;rsquo;t get a proper announce. There are more GUI
libraries for CL.&lt;/p&gt;

&lt;p&gt;demos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mstdn.io/@veer66/111024762876056271&#34;&gt;&amp;ldquo;cl-gtk4 combines strength of GTK and Common Lisp interactive development.&amp;rdquo; (short screencast)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;web&#34;&gt;Web&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CLOG&lt;/strong&gt; appeared in 2022 and is kicking. Its API has been stable for 4 years.&lt;/p&gt;

&lt;p&gt;You know Hacker News, the website, right? &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1iekqnc/the_production_website_of_hacker_news_now_runs_on/&#34;&gt;&lt;strong&gt;Hacker News now runs on top of SBCL&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HN runs on top of Arc, the language.
Arc was implemented on top of Racket (-&amp;gt; MzScheme).
A new, faster / more efficient, implementation of Arc in SBCL was in the works by a Hacker News site maintainer for some time: called Clarc. Its source code has not been published.
Since [late september, 2024], the official Hacker News site runs using Clarc and SBCL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here&amp;rsquo;s (again) my &lt;strong&gt;new resource for web development&lt;/strong&gt; in Common Lisp: &lt;a href=&#34;https://web-apps-in-lisp.github.io/index.html&#34;&gt;Web Apps in Lisp: Know-how&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now the links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLOG CLOG 2.0 - Now with a complete Common Lisp &lt;strong&gt;IDE&lt;/strong&gt; and &lt;strong&gt;GUI Builder&lt;/strong&gt; (with or w/o emacs)&lt;/li&gt;
&lt;li&gt;CLOG OS shell&lt;/li&gt;
&lt;/ul&gt;



&lt;img src=&#34;https://preview.redd.it/p668uwf3kytc1.png?width=1720&amp;format=png&amp;auto=webp&amp;s=86cbed5246b73eb38bb00afbebee4fa71c30626d&#34;
  style=&#34;max-width: 100%; margin: 2em;&#34; alt=&#34;CLOG shell&#34; title=&#34;CLOG shell&#34;&gt;&lt;/img&gt;



&lt;ul&gt;
&lt;li&gt;CLOG &lt;a href=&#34;https://youtu.be/k3V75qWQHNE?feature=shared&#34;&gt;CLOG Builder Video Manual Video 5 - Using Projects &amp;amp; Plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CLOG debug tools &lt;a href=&#34;https://github.com/rabbibotton/clog/discussions/361&#34;&gt;https://github.com/rabbibotton/clog/discussions/361&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CLOG got emacs-like tabs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Projects built with CLOG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/mmontone/mold-desktop&#34;&gt;mold desktop&lt;/a&gt; - A programmable desktop.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1bztxs8/clog_moldable_inspector/&#34;&gt;CLOG moldable inspector&lt;/a&gt;, &amp;ldquo;A moldable Common Lisp object inspector based on CLOG&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;



&lt;a href=&#34;https://codeberg.org/mmontone/mold-desktop&#34;&gt;
&lt;img src=&#34;https://codeberg.org/mmontone/mold-desktop/media/branch/master/screenshots/screenshot2.webp&#34;
  style=&#34;max-width: 100%; margin: 2em;&#34; alt=&#34;moldable desktop&#34; title=&#34;Web-based moldable desktop built in CLOG.&#34;&gt;&lt;/img&gt;
&lt;/a&gt;



&lt;p&gt;&lt;strong&gt;Weblocks&lt;/strong&gt; (continued in the Reblocks project):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://40ants.com/reblocks/extensions/&#34;&gt;Height Weblocks (Reblocks) Extensions - now with documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;video: &lt;a href=&#34;https://diode.zone/videos/watch/9e379a86-c530-4e9d-b8be-7437b1f7200b&#34;&gt;Weblocks demo: a staff onboarding web app written in Common Lisp (EN Subs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/173st0r/a_wasm_common_lisp_repl/&#34;&gt;A &lt;strong&gt;WASM&lt;/strong&gt; Common Lisp REPL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://nmunro.github.io/2025/01/30/ningle-3.html&#34;&gt;Ningle Tutorial 3: Static Files Middleware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/towards-a-database-admin-dashboard-for-common-lisp/&#34;&gt;Towards a &lt;strong&gt;Django-like database admin dashboard&lt;/strong&gt; for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://boogs.life/add-billing-to-your-common-lisp-app/index.html&#34;&gt;Add &lt;strong&gt;Stripe billing&lt;/strong&gt; to your Common Lisp app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.screenshotbot.io/2024/08/10/building-a-highly-available-web-service-without-a-database/&#34;&gt;Building a highly-available web service without a database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nickfa.ro/wiki/Building_with_Parenscript_and_Preact&#34;&gt;Building with Parenscript and Preact&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/i18n-in-my-lisp-web-app-with-djula-templates-and-gettext/&#34;&gt;i18n in my Lisp web app with Djula templates and gettext &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;videos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/11vlsgl/how_to_create_new_cl_library_or_webapplication/&#34;&gt;How to create new CL library or web-application using the Mystic project generator &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/117oq9r/jzon_hits_10_and_is_at_last_on_the_latest_ql/&#34;&gt;JZON hits 1.0 and is at last on the latest QL release: a &lt;strong&gt;correct and safe JSON parser&lt;/strong&gt;, packed with features, and also FASTER than the latest JSON library advertised here.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kilianmh/openapi-generator&#34;&gt;&lt;strong&gt;OpenAPI&lt;/strong&gt; client generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1f6kc5o/pulling_portableaserve_portable_allegroserve_into/&#34;&gt;Pulling portableaserve (Portable AllegroServe) into sharplispers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/scrapycl&#34;&gt;ScrapyCL - The web scraping framework for writing crawlers in Common Lisp &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1h0bx3z/nobody_knows_shoes_but_ryo_shoes_a_simple_gui_dsl/&#34;&gt;Nobody Knows Shoes But Ryo Shoes (A Simple GUI DSL upon CLOG)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;web views&lt;/strong&gt; I mentioned: Electron is a thing, but today we have bindings to webview.h and webUI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/three-web-views-for-common-lisp--cross-platform-guis/&#34;&gt;Three web views for Common Lisp: build cross platform GUIs with Electron, WebUI or CLOG Frame&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;nyxt-4-0-pre-realease-now-on-electron&#34;&gt;Nyxt 4.0 pre-realease - now on Electron&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://nyxt.atlas.engineer/article/release-4.0.0-pre-release-1.org&#34;&gt;Nyxt 4.0-pre-release-1&lt;/a&gt; was published in late 2024.&lt;/p&gt;

&lt;p&gt;They are publishing a Flatpak featuring the legacy WebKitGTK port and a new Electron one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Electron has better performance and opens the door for macOS and Windows support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&#34;more-libraries&#34;&gt;More libraries&lt;/h1&gt;

&lt;p&gt;Data structures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/slburson/fset/releases&#34;&gt;fset 1.4 - bug fixes and minor improvements &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://scottlburson2.blogspot.com/2024/10/comparison-fset-vs-sycamore.html&#34;&gt;Comparison: FSet vs. Sycamore (and FSet speed-up)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Language extensions, core libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://turtleware.eu/posts/Dynamic-Let.html&#34;&gt;Dynamic Let (Common Lisp, MOP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://scottlburson2.blogspot.com/2024/09/equality-and-comparison-in-fset.html&#34;&gt;Equality and Comparison in FSet, CDR8, generic-cl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/alex-gutev/generic-cl/releases/tag/v1.0&#34;&gt;generic-cl 1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/edicl/cl-ppcre/releases/tag/v2.1.2&#34;&gt;cl-ppcre 2.1.2 - New function: count-matches&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Iteration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fosskers/cl-transducers/&#34;&gt;cl-transducers 1.0 - operating over and into plists, hash-tables, CSV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fosskers/cl-transducers/releases/tag/v1.2.0&#34;&gt;cl-transducers 1.2.0 - FSet support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tfeb.org/fragments/2024/05/15/an-iteration-construct-for-common-lisp/&#34;&gt;Štar: an iteration construct for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developer tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.funcall.org//breaking-the-kernighans-law/&#34;&gt;BRAKE, an extended breakpoint facility for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Threads, actors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.cddr.org/posts/2023-05-27-bordeaux-threads-apiv2/&#34;&gt;Bordeaux-Threads API v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mdbergmann/cl-gserver&#34;&gt;Sento actor framework 3.0 released - no new features, many API changes: cleanups, obstacles removed, and hopefully a more consistent way of doing things.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mdbergmann/cl-gserver/releases/tag/3.2.0&#34;&gt;Sento 3.2 · allows a throughput of almost 2M messages per second&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Documentation builders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/HectareaGalbis/adp-github/tree/main&#34;&gt;Add Documentation, Please&amp;hellip; with Github Flavoured Markdown · supports cross references and table of contents.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Databases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://allegrograph.com/blog/&#34;&gt;AllegroGraph 8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/marijnh/Postmodern/releases/&#34;&gt;Postmodern v1.33.10 and 1.33.11 released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/endatabas/endb/releases/tag/v0.2.0-beta.1&#34;&gt;endatabas/endb v0.2.0-beta.1 · SQL document database with full history (Lisp, Rust)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/daninus14/mito-validate&#34;&gt;Mito-validate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;relational database and first order logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ap5.com/&#34;&gt;AP5 - an extension to commonlisp which allows users to &amp;ldquo;program&amp;rdquo; in a model of first order logic or a relational database (1990, last update 2024)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Numerical and scientific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hikettei/cl-waffe2&#34;&gt;cl-waffe2: (Experimental) Graph and Tensor Abstraction for Deep Learning all in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://digikar99.github.io/numericals/manual/&#34;&gt;numericals` has a slightly better documentation now!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/18isr9q/common_lisp_numerical_and_scientific_computing/&#34;&gt;Common Lisp: Numerical and Scientific Computing - Call for Needs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-stat.dev/blog/2023/12/29/2023-end-of-year-summary/&#34;&gt;Lisp Stats 2023 end of year summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mahmoodsheikh36.github.io/post/20230510181916-maxima_in_lisp/&#34;&gt;More notes on using Maxima in a Lisp runtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git.sr.ht/~jmbr/maxima-interface&#34;&gt;maxima-interface - Simple interface between Common Lisp and Maxima&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plotting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1c31559/gurafu_a_simple_just_usable_plot_program_for/&#34;&gt;GURAFU: a simple (just usable) plot program for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ajberkley/plotly-user&#34;&gt;plotly-user: Use plotly in your browser to explore data from a Common Lisp REPL&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;a week-end hack and an excuse to learn CLOG&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bindings and interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/marcoheisig/lang&#34;&gt;marcoheisig/lang: A library for &lt;strong&gt;seamless multi-language programming&lt;/strong&gt;. The currently supported languages are Python and Lisp.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1bpig73/bike_net_interface_for_cl_version_0140/&#34;&gt;bike (.NET interface for CL) version 0.14.0. Documentation! .NET-callable classes. ECL support. And more.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Islam0mar/CL-CXX-JIT&#34;&gt;CL-CXX-JIT: Write C++ functions within Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gmpalter/cl-forth&#34;&gt;Common Lisp implementation of the Forth 2012 Standard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Serialization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/1hz5879/new_binary_serializationdeserialization_library/&#34;&gt;New binary serialization/deserialization library: cl-binary-store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/19d5j6a/clnaivestore_new_version/&#34;&gt;cl-naive-store: new version&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Date and time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://shinmera.github.io/precise-time/&#34;&gt;Precise Time - hooking into the operating system to give sub-seconds precise timing information&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/copyleft/calendar-times&#34;&gt;calendar-times - a calendar time library implemented on top of LOCAL-TIME&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Utilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/cl-ansi-term--print-tables-with-style-and-other-script-utilities/&#34;&gt;cl-ansi-term: print tables with style, and other script utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git.sr.ht/~whereiseveryone/command-line-args&#34;&gt;command-line-args - Turn your Common Lisp function into a command which you can use from the command line.&lt;/a&gt; (similar to &lt;a href=&#34;https://github.com/40ants/defmain&#34;&gt;defmain&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lisp-maintainers/file-finder/&#34;&gt;file-finder: Rapid file search and inspection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.chiark.greenend.org.uk/pipermail/sgo-software-announce/2024/000089.html&#34;&gt;Consfigurator 1.4.1 released, including new support for FreeBSD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bindings and interfaces to other software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cl-git.russellsim.org/changelog.html#id2&#34;&gt;cl-git 2.0 - an interface to the C library libgit2. The API is an almost complete exposure of the underlying library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://40ants.com/cl-telegram-bot/&#34;&gt;cl-telegram-bot - Telegram Bot API (now with documentation)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bohonghuang/claw-raylib&#34;&gt;claw-raylib - Fully auto-generated Common Lisp bindings to Raylib and Raygui using claw and cffi-object&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Networking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dtqec/aether&#34;&gt;aether · Distributed system emulation in Common Lisp &lt;/a&gt; &lt;a href=&#34;https://www.youtube.com/watch?v=CGt2rDIhNro&#34;&gt;ELS talk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;scripting&#34;&gt;Scripting&lt;/h2&gt;

&lt;p&gt;(I love what&amp;rsquo;s being done here)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ruricolist/kiln&#34;&gt;ruricolist/kiln: Infrastructure for scripting in Common Lisp to make Lisp scripting efficient and ergonomic.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=41401415&#34;&gt;CIEL Is an Extended Lisp, Hacker News&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/neomacs-project/unix-in-lisp&#34;&gt;unix-in-lisp&lt;/a&gt; -  Mount Unix system into Common Lisp image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;software-releases&#34;&gt;Software releases&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://i.redd.it/ffb8gu6zobta1.png&#34;&gt;OpusModus 3.0, first Windows version released&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=38188788&#34;&gt;HN discussion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tamurashingo/reddit1.0/&#34;&gt;tamurashingo/reddit1.0: Refactored &lt;strong&gt;old reddit source code&lt;/strong&gt; (with recent commits and a Docker setup)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/VitoVan/calm/releases/tag/1.0.0&#34;&gt;Release 1.0.0 · calm - Canvas and Lisp magic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/youngde811/Lisa&#34;&gt;Lisa: A production-ready &lt;strong&gt;expert-system&lt;/strong&gt; shell, written in thoroughly modern Common Lisp.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/KikyTokamuro/todolist-cl&#34;&gt;todolist-cl 3.0 - a todolist web UI, written in Common Lisp, with Hunchentoot, Spinneret templates, Mito ORM.&lt;/a&gt; (by a CL newcomer)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/glv/iescrypt&#34;&gt;iescrypt: a tool to encrypt and/or sign files. Lisp and C versions.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;other-articles&#34;&gt;Other articles&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fosskers.ca/en/blog/rounds-of-lisp&#34;&gt;&lt;strong&gt;A Tour of the Lisps&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.djhaskin.com/blog/why-i-chose-common-lisp/&#34;&gt;Why I chose Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Lisp-Stat/IPS9/blob/master/notebooks/Part%20I/Chapter%201%20Looking%20at%20Data.ipynb&#34;&gt;practicing statistics with Common Lisp (Jupyter notebook)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/18t09pf/full_common_lisp_sbcl_and_a_clog_dev_environment/&#34;&gt;Full Common Lisp (sbcl) and a CLOG dev environment on/from an Android device&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;videos&#34;&gt;Videos&lt;/h1&gt;

&lt;p&gt;Demos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=gdjkSkRFcr4&#34;&gt;AudioVisual in CommonLisp (cl-collider, cl-visual) (screencast)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/liaLgaTOpYE&#34;&gt;Cheesy trailer for recent kons-9 &lt;strong&gt;3D graphics&lt;/strong&gt; features.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=jS84KmkkNkU&#34;&gt;Drum N Bass in CommonLisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=ah7jfWd5m9A&#34;&gt;Drum and Bass with a Counterpoint - How to Tutorial - Opusmodus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=fytGL8vzGeQ&#34;&gt;How Lisp is designing &lt;strong&gt;Nanotechnology&lt;/strong&gt; (Developer Voices, with Prof. Christian Schafmeister) (Youtube)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=lGS4sr6AzKw&#34;&gt;How to Package Common Lisp Software for Linux? EN Subs (alien-works-delivery, linux-packaging)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=G7KwJp9UAd8&#34;&gt;Melodic Techno - How to Tutorial - &lt;strong&gt;Opusmodus&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=3lruQIx1Rds&#34;&gt;The Opusmodus Studio - Everything I didn&amp;rsquo;t know I needed - Subject Sound (YouTube) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=BMoHE96rh7w&#34;&gt;Welcome to Opusmodus (Youtube)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=8QCbp7ct2w0&#34;&gt;Identicons and Clozure Common Lisp, by R. Matthew Emerson&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Web:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/18wkr41/dynamic_page_with_htmx_and_common_lisp/&#34;&gt;Dynamic Page With &lt;strong&gt;HTMX&lt;/strong&gt; and Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=EFRVHmOCE7Q&#34;&gt;Common Lisp web development tutorial: &lt;strong&gt;how to build a web app in Lisp&lt;/strong&gt; · part 2&lt;/a&gt; &lt;a href=&#34;https://www.youtube.com/watch?v=h_noB1sI_e8&#34;&gt;part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/sYgA7Nt3rvo&#34;&gt;Missing &lt;strong&gt;Clack&lt;/strong&gt; Guide! Build a Web Application in Common Lisp Like a Pro! &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/smTG3niedsg&#34;&gt;&lt;strong&gt;URL shortener&lt;/strong&gt; using Hunchentoot and BKNR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/ZGgvDj00SZE&#34;&gt;web page graphics with &lt;strong&gt;lisp-stat, data-frame and vega plot&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More from the ELS (see their Youtube channel):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://zenodo.org/records/11062314&#34;&gt;An Introduction to &lt;strong&gt;Array Programming&lt;/strong&gt; in Petalisp, by Marco Heisig, ELS 2024 &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://yewtu.be/watch?v=7IpnmXnO1RU&#34;&gt;Lightning Talk: &lt;strong&gt;Julia&lt;/strong&gt; Functions, Now in Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/k6zkOTdTiF8?si=eT3yGHJ_ef4Suz7s&#34;&gt;Lightning Talk: Valtan: Write Webapp Everything in Common Lisp: European Lisp Symposium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/u-jdqpZFlkA&#34;&gt;ELS2023: Common Lisp Foundation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/17-new-videos-on-common-lisp-macros/&#34;&gt;I published 17 videos about Common Lisp macros - &lt;strong&gt;learn Lisp with a code-first tutorial&lt;/strong&gt;&lt;/a&gt; &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/16jh8pk/i_published_17_videos_about_common_lisp_macros/&#34;&gt;comments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/common_lisp/comments/1c3pre6/common_lisp_study_group_experiments_with_cffi/&#34;&gt;Common Lisp Study Group: experiments with CFFI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/cssHR_MLwNQ&#34;&gt;CLOS: Introduction and usage of defclass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=5-Ug1gitygQ&#34;&gt;Nekoma Talks #19 - Common Lisp from &lt;strong&gt;a Clojurian perspective&lt;/strong&gt; Part 2 (YouTube)&lt;/a&gt;, &lt;a href=&#34;https://www.youtube.com/watch?v=NgI14YHVI-I&#34;&gt;part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/eTgDaMREKT4&#34;&gt;Review of &lt;strong&gt;8 Common Lisp IDEs&lt;/strong&gt;! Which one to choose? (EN Subs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aaaand that&amp;rsquo;s it for the tour of the last couple years. Tell me if I missed something. I&amp;rsquo;ll keep updating this post for a few days.&lt;/p&gt;

&lt;p&gt;Happy lisping and show us what you build!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New resource specialized on web development in Common Lisp</title>
      <link>/blog/new-resource-web-development-in-common-lisp/</link>
      <pubDate>Wed, 15 Jan 2025 10:39:53 +0100</pubDate>
      
      <guid>/blog/new-resource-web-development-in-common-lisp/</guid>
      <description>&lt;p&gt;I just released a new documentation website specialized on web development in Common Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://web-apps-in-lisp.github.io/&#34;&gt;https://web-apps-in-lisp.github.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;rsquo;d be embarrassed to tell how long it took me to grasp all the
building blocks and to assemble a resource that makes sense. I hope it
serves you well, now don&amp;rsquo;t hesitate to share what you are building, it
creates emulation!&lt;/p&gt;

&lt;p&gt;In the first tutorial we build a simple app that shows a web
form that searches and displays a list of products.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://web-apps-in-lisp.github.io/tutorial/web-app.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;We see many necessary building blocks to write web apps in Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to start a server&lt;/li&gt;
&lt;li&gt;how to create routes&lt;/li&gt;
&lt;li&gt;how to define and use path and URL parameters&lt;/li&gt;
&lt;li&gt;how to define HTML templates&lt;/li&gt;
&lt;li&gt;how to run and build the app, from our editor and from the terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In doing so, we&amp;rsquo;ll experience the interactive nature of Common Lisp.&lt;/p&gt;

&lt;p&gt;In the user log-in section, we build a form that checks a user name and a password:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://web-apps-in-lisp.github.io/building-blocks/login.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;We also introduce databases, and more topics.&lt;/p&gt;

&lt;p&gt;The sources are here: &lt;a href=&#34;https://github.com/web-apps-in-lisp/web-apps-in-lisp.github.io/&#34;&gt;https://github.com/web-apps-in-lisp/web-apps-in-lisp.github.io/&lt;/a&gt; and the GitHub Discussions are open.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Towards a Django-like database admin dashboard for Common Lisp</title>
      <link>/blog/towards-a-database-admin-dashboard-for-common-lisp/</link>
      <pubDate>Mon, 30 Dec 2024 17:23:14 +0100</pubDate>
      
      <guid>/blog/towards-a-database-admin-dashboard-for-common-lisp/</guid>
      <description>

&lt;p&gt;This is an ongoing work I wanted to share sometimes this year. It isn&amp;rsquo;t ready,
it isn&amp;rsquo;t released, but if you are a motivated lisper I can add you to
the GitHub repository and you can try the demo.&lt;/p&gt;

&lt;p&gt;We all want more tools for easier and faster web development
in CL I guess right? An automatic database admin dashboard is an important
component for me, both for personal use and development purposes, but
also for client-facing apps, at least at the beginning of a project.&lt;/p&gt;



&lt;img src=&#34;/images/db-admin/light-theme.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;What I started is based on the Mito ORM. You define your DB tables as
usual, and then this package comes into play. Let&amp;rsquo;s call it
&lt;code&gt;mito-admin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What&amp;rsquo;s more or less working so far is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose which tables to display (let&amp;rsquo;s say we have &lt;code&gt;books&lt;/code&gt;, that can be in one &lt;code&gt;shelf&lt;/code&gt;, and have many &lt;code&gt;tags&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;you get a welcome page. The tables are listed on the left side of the admin.&lt;/li&gt;
&lt;li&gt;click on a table and see a &lt;strong&gt;list of records&lt;/strong&gt; (with &lt;strong&gt;pagination&lt;/strong&gt;, which module is already published as &lt;a href=&#34;https://github.com/cosmoframework/cosmo-pagination&#34;&gt;cosmo-pagination&lt;/a&gt;. See also &lt;a href=&#34;https://github.com/mmontone/lisp-pagination/&#34;&gt;lisp-pagination&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CRUD&lt;/strong&gt; actions on records:

&lt;ul&gt;
&lt;li&gt;create&lt;/li&gt;
&lt;li&gt;update&lt;/li&gt;
&lt;li&gt;delete&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;with &lt;strong&gt;CSRF protection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;with &lt;strong&gt;form validation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;with automatic handling of &lt;strong&gt;relations&lt;/strong&gt; and custom &lt;strong&gt;HTML widgets&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;a one-to-many gives you a select field&lt;/li&gt;
&lt;li&gt;(there&amp;rsquo;s a lot to do here)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;search bar&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;built-in &lt;strong&gt;login, user auth and rights&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;all this being customizable with CLOS fields and methods&lt;/li&gt;
&lt;li&gt;light and dark themes thanks to Bulma CSS&lt;/li&gt;
&lt;li&gt;for SQLite, Postgres, MySQL.&lt;/li&gt;
&lt;/ul&gt;



&lt;img src=&#34;/images/db-admin/login.png&#34; style=&#34;max-width: 100%&#34;/&gt;





&lt;img src=&#34;/images/db-admin/books.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#models&#34;&gt;Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#select-tables-to-show&#34;&gt;Select tables to show&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#start-the-admin&#34;&gt;Start the admin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#configure-the-admin&#34;&gt;Configure the admin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#form-handling&#34;&gt;Form handling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#form-validation&#34;&gt;Form validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#one-to-many-relations&#34;&gt;One-to-many relations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#many-to-many-relations&#34;&gt;Many-to-many relations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-words&#34;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;p&gt;There&amp;rsquo;s a demo in the project. Here&amp;rsquo;s how it works.&lt;/p&gt;

&lt;h2 id=&#34;models&#34;&gt;Models&lt;/h2&gt;

&lt;p&gt;Here are 3 Mito models: a book, a shelf, tags.&lt;/p&gt;

&lt;p&gt;This is regular Mito and regular classes definitions (note the :metaclass option).&lt;/p&gt;

&lt;p&gt;We are excluding the &lt;code&gt;print-object&lt;/code&gt; methods for brevity.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(in-package :mito-admin-demo)

(defparameter *db-name* &amp;quot;db.db&amp;quot;
  &amp;quot;SQLite DB name.&amp;quot;)

(defvar *db* nil
  &amp;quot;DB connection object.&amp;quot;)

(defclass shelf ()
  ((name
    :initarg :shelf
    :accessor name
    :initform &amp;quot;&amp;quot;
    :col-type (or :null (:varchar 128))))
  (:metaclass mito:dao-table-class)
  (:documentation &amp;quot;Shelf: where is the book located.&amp;quot;)
  (:unique-keys name))

(defclass tag ()
  ((name
    :initarg :name
    :accessor name
    :initform nil
    :col-type (or :null (:varchar 128))))
  (:metaclass mito:dao-table-class)
  (:documentation &amp;quot;A book can have many tags (categories).&amp;quot;)
  (:unique-keys name))

;; necessary intermediate table for m2m.
(defclass book-tags ()
  ((book :references book)
   (tag :col-type tag))
  (:metaclass mito:dao-table-class))


(defclass book ()
  ((title
    :accessor title
    :initarg :title
    :initform nil
    :type string
    :col-type (:varchar 128))

   (title-ascii
     :accessor title-ascii
     :initform nil
     :col-type (:varchar 128))
     :documentation &amp;quot;Same title, only ascii. Processed after the book creation. Used for search and URI slugs.&amp;quot;)

   (shelf
    :accessor shelf
    :initform nil
    :col-type (or :null shelf)
    :documentation &amp;quot;A card has only one shelf.&amp;quot;)

   (tags
    ;; This column is even optional, we can do everything with the intermediate table
    ;; and a method that collects the tag for a book.
    ;; In fact, this slot won&#39;t be populated by Mito, we&#39;ll see &amp;quot;slot unbound&amp;quot;.
    :accessor tags
    :initform nil
    :col-type (or :null book-tags)
    :documentation &amp;quot;A book can have many tags, aka categories.&amp;quot;)

   (cover-url
    :accessor cover-url
    :initarg :cover-url
    :initform nil
    :type (or string null)
    :col-type (or (:varchar 1024) :null))

   (review
    :accessor review
    :initarg :review
    :initform nil
    :type (or string null)
    :col-type (or :text :null)
    :documentation &amp;quot;Let&#39;s write reviews about our favourite books.&amp;quot;))

  (:metaclass mito:dao-table-class)
  (:documentation   &amp;quot;Book class, simplified. After modification of the DB schema, run (migrate-all).&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To create the database, you&amp;rsquo;ll need a couple more Mito
invocations. See &lt;a href=&#34;https://github.com/fukamachi/mito/&#34;&gt;its README&lt;/a&gt; or the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;Cookbook&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;select-tables-to-show&#34;&gt;Select tables to show&lt;/h2&gt;

&lt;p&gt;We need to select the tables we&amp;rsquo;ll make available in the admin.&lt;/p&gt;

&lt;p&gt;Override the &lt;code&gt;mito-admin::tables&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod mito-admin::tables ()
  &#39;(
    book
    shelf
    tag
    ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I deleted some inline comments, but there&amp;rsquo;s something to keep in
mind. We need a list of &lt;em&gt;all&lt;/em&gt; classes &lt;em&gt;for Mito&lt;/em&gt;, so that it runs the
migrations, and another one of &lt;em&gt;a subset&lt;/em&gt; of classes &lt;em&gt;for the
admin&lt;/em&gt;. There&amp;rsquo;s only one list for now but that&amp;rsquo;s easy to fix.&lt;/p&gt;

&lt;h2 id=&#34;start-the-admin&#34;&gt;Start the admin&lt;/h2&gt;

&lt;p&gt;Call &lt;code&gt;mito-admin:connect&lt;/code&gt;, and bootstrap users and their base roles:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;    ;; users and roles:
    (mito-admin-auth/v1::ensure-users-and-roles)

    ;; base roles.
    (mito-admin-auth/v1::bootstrap-base-roles)
&lt;/code&gt;&lt;/pre&gt;



&lt;img src=&#34;/images/db-admin/admin.png&#34; style=&#34;max-width: 100%&#34; title=&#34;This view is useless for now, but it&#39;s the landing page.&#34;/&gt;



&lt;h2 id=&#34;configure-the-admin&#34;&gt;Configure the admin&lt;/h2&gt;

&lt;p&gt;The first thing to do is to register an app name:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito-admin::register-app :cosmo-admin-demo)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which is here our lisp&amp;rsquo;s package. Working in a Lisp image allows to
work on multiple (web) apps at the same time (at least with
Hunchentoot). So, in a web library you&amp;rsquo;ll need a layer of indirection
if you want to support this use case. I don&amp;rsquo;t for now, but registering
the app&amp;rsquo;s &lt;code&gt;*package*&lt;/code&gt; is necessary internally to resolve table names
to fully-qualified symbols. As a user, you shouldn&amp;rsquo;t need to know all
that, but as a tester you might.&lt;/p&gt;

&lt;p&gt;You can override the &lt;code&gt;render-slot&lt;/code&gt; method to change the default
representation of a record&amp;rsquo;s slot. Here we turn a book&amp;rsquo;s &lt;code&gt;cover-url&lt;/code&gt;
from a string to an HTML anchor. This can be automated and
abstracted. Another TODO.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod mito-admin::render-slot ((obj book) (slot (eql &#39;cover-url)))
  &amp;quot;A book cover URL must be a &amp;lt;a&amp;gt; tag with an href.&amp;quot;
  (if (str:non-blank-string-p (mito-admin::slot-value? obj slot))
      (format nil &amp;quot;&amp;lt;a href=\&amp;quot;~a\&amp;quot;&amp;gt; ~a &amp;lt;/a&amp;gt;&amp;quot; val val)
      &amp;quot;&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;



&lt;img src=&#34;/images/db-admin/book.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;h2 id=&#34;form-handling&#34;&gt;Form handling&lt;/h2&gt;

&lt;p&gt;This is the most important, and unfinished, part of the admin.&lt;/p&gt;

&lt;p&gt;We could maybe use &lt;a href=&#34;https://github.com/mmontone/cl-forms&#34;&gt;cl-forms&lt;/a&gt;
but I didn&amp;rsquo;t find that it maps well to this admin&amp;rsquo;s ABI. You
might find it useful though, as it&amp;rsquo;s feature complete. It even has:
client-side validation, sub-forms, Spinneret and Djula-based
renderers, etc. Look at its demo.&lt;/p&gt;

&lt;p&gt;We need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;be able to include and exclude fields from the HTML forms&lt;/li&gt;
&lt;li&gt;be able to choose a different HTML widget for a given field&lt;/li&gt;
&lt;li&gt;validate forms

&lt;ul&gt;
&lt;li&gt;with custom validation logic&lt;/li&gt;
&lt;li&gt;and nicely render errors&lt;/li&gt;
&lt;li&gt;or create or update the records.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We currently need to create forms explicitely:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito-admin:define-forms &#39;(shelf tag))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or also&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; We can define forms manually.
;; (we can override default slots, but we can also override them by redefining the accessor methods)
(defclass book-form (mito-admin::form)
  ())
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A &lt;code&gt;form&lt;/code&gt; class has several slots we may redefine and use later, such
as a list of validators, or the fields to use for the search, fields
to exclude, etc.&lt;/p&gt;

&lt;p&gt;We can exclude fields:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod mito-admin::exclude-fields (book-form)
  &amp;quot;Return a list of field names (symbols) to exclude from the creation form.&amp;quot;
  &#39;(title-ascii
    ;; TODO: handle relations
    ;; we need to exclude shelf, or we&#39;ll get an error on mito:insert-dao if the field is NIL.
    ;; shelf
    shelf-id
    tags-id
    ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you see, there are more TODOs here. &lt;code&gt;title-ascii&lt;/code&gt; is a private
field that we don&amp;rsquo;t need to expose. That&amp;rsquo;s fine. &lt;code&gt;shelf-id&lt;/code&gt; and all
are Mito&amp;rsquo;s references to the other tables. We need to recognize
them and exclude them.&lt;/p&gt;

&lt;p&gt;To define an HTML widget, override &lt;code&gt;mito-admin::field-input&lt;/code&gt;. Our demo
uses a built-in template to render a select field from a list of options.&lt;/p&gt;



&lt;img src=&#34;/images/db-admin/form-select.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;TODOs: there&amp;rsquo;s a lot to do here. Our admin app still requires too much
configuration, we want it to be more automatic. Recognize the input
types better, ship an async &lt;a href=&#34;https://select2.org/&#34;&gt;select2&lt;/a&gt; input for
many-to-many relations.&lt;/p&gt;

&lt;h2 id=&#34;form-validation&#34;&gt;Form validation&lt;/h2&gt;

&lt;p&gt;To validate a record, override the &lt;code&gt;validators&lt;/code&gt; method. It returns a
hash-table that, for all the table&amp;rsquo;s fields, associates a list of
validators.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod mito-admin::validators ((obj (eql &#39;book)))
  &amp;quot;To validate a book:

  - its title should not be equal to \&amp;quot;test\&amp;quot;.

  Beware that we override the method MITO-ADMIN::VALIDATORS.&amp;quot;
  (serapeum:dict &#39;title (clavier:~= &amp;quot;test&amp;quot;
                                    &amp;quot;this title is too common, please change it!&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use the &lt;a href=&#34;https://github.com/mmontone/clavier&#34;&gt;clavier&lt;/a&gt; library for
this. Here&amp;rsquo;s a short &lt;a href=&#34;https://dev.to/vindarel/form-validation-in-common-lisp-4h29&#34;&gt;blog post&lt;/a&gt;
that shows a quick usage and our &lt;code&gt;:allow-blank&lt;/code&gt; passthrough and
&lt;code&gt;validate-all&lt;/code&gt; function (which were &lt;a href=&#34;https://github.com/mmontone/clavier/pull/10&#34;&gt;not
accepted upstream&lt;/a&gt; btw (shit it was nearly a year ago)).&lt;/p&gt;

&lt;p&gt;Our form validation mechanism shows a global error message, and a specific one under each input field.&lt;/p&gt;

&lt;p&gt;You didn&amp;rsquo;t write a single HTML line for this o/&lt;/p&gt;



&lt;img src=&#34;/images/db-admin/form-error.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;h2 id=&#34;one-to-many-relations&#34;&gt;One-to-many relations&lt;/h2&gt;

&lt;p&gt;Those are correctly handled by Mito and it&amp;rsquo;s easy to have a custom widget in the admin.&lt;/p&gt;

&lt;h2 id=&#34;many-to-many-relations&#34;&gt;Many-to-many relations&lt;/h2&gt;

&lt;p&gt;See here: &lt;a href=&#34;https://github.com/fukamachi/mito/discussions/161&#34;&gt;https://github.com/fukamachi/mito/discussions/161&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At present, Mito doesn&amp;rsquo;t do much for m2m relations, but we can simply
write a short method that will select all related objects of a record.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s for a book&amp;rsquo;s tags:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod tags (obj)
  ;; null case
  nil)

(defmethod tags ((obj book))
  (let ((book-tags
            (mito:select-dao &#39;book-tags
                (sxql:where (:= :book-id
                                (mito:object-id obj))))))
    (when book-tags
     (mapcar #&#39;tag book-tags))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How to use it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(tags (mito:find-dao &#39;book))
;; =&amp;gt; (#&amp;lt;TAG tag1&amp;gt; #&amp;lt;TAG tag2&amp;gt;)

(tags (mito:find-dao &#39;book :id 2))
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Simple enough, but that&amp;rsquo;s another TODO: automate the creation of such methods.&lt;/p&gt;

&lt;h2 id=&#34;closing-words&#34;&gt;Closing words&lt;/h2&gt;

&lt;p&gt;This project has too many moving parts to my taste but I&amp;rsquo;ll get there.&lt;/p&gt;

&lt;p&gt;I hate when people don&amp;rsquo;t release their useful library because &amp;ldquo;the
code is meh&amp;rdquo; and yes, I&amp;rsquo;m doing that to you.&lt;/p&gt;

&lt;p&gt;However I extracted parts from
&lt;a href=&#34;https://github.com/OpenBookStore/openbookstore&#34;&gt;OpenBookStore&lt;/a&gt; (WIP)
(notably the login, users auth and rights which was contributed by
gnuxie), I published the little pagination module, contributed to a
couple libraries and wrote blog posts. It&amp;rsquo;s already that for you.&lt;/p&gt;

&lt;p&gt;You are at the very least helping as duck-brainstorming, so thanks. If
you&amp;rsquo;d like to try the demo and look at horrible code, it should be doable.&lt;/p&gt;

&lt;p&gt;I wonder under which license I&amp;rsquo;ll publish that.&lt;/p&gt;

&lt;p&gt;There might be other ways for an admin panel and please try and
cook us a plug-and-play solution. The proprietary Airtable with the new
&lt;a href=&#34;https://github.com/qubit55/cl-airtable&#34;&gt;cl-airtable&lt;/a&gt; library or the
open-source NocoDB (they give you a spreadsheet-like web UI + an API),
or the lightweight Pocketbase, Mathesar or Supabase for Postgres
(would you give this to your non-tech-savvy clients?),
or NodeJS-based admin panels, etc, etc, etc. But a pure
Common Lisp one? We&amp;rsquo;ll talk more about it in less than ten years,
fingers crossed.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;You can &lt;a href=&#34;https://github.com/sponsors/fukamachi&#34;&gt;support E. Fukamachi&lt;/a&gt; for his work on
Mito, cl-dbi, SxQL and all his other useful libraries.&lt;/p&gt;

&lt;h2 id=&#34;appendix-todos&#34;&gt;Appendix: TODOs&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-txt&#34;&gt;View:

- [X] list of tables
- [-] list of records for each table
  - [X] see records
  - [X] pagination
  - [X] add &amp;quot;create&amp;quot; button
  - [ ] choose fields to display in search result
  - [ ] order records by field
- [X] a specific record
  - [X] view related column
  - [X] view some fields, ignore some fields

Search:

- [X] lax search on given fields
- [ ] more criteria

Create:

- [-] create a record
  - [X] ignore some fields
  - [X] choose related column
    - [X] select input for a to-1 relationship
    - [-] have a usable input widget for many-to-many relationships
      - [X] define a many-to-many in the demo: a book can have many tags.
      - [ ] define a default input widget (probably select2)
      - Mito doesn&#39;t help much with many-to-manys though.
  - [-] form handling
    - [X] form validation
      - [X] basics
    - [X] CSRF protection
      - in the create and edit forms.
  - [ ] form handling (cont)
    - [ ] subforms (create a new shelf in the card form)
    - [ ] client-side validation

Update:

- [X] update an existing record
  - [X] with same mechansim as create

Demo:

- [X] demo project with a couple tables and fields
  - [X] decouple the POC from openbookstore. Shit that wasn&#39;t that
    easy. &amp;lt;2024-03-21&amp;gt;
- [ ] display the app name instead of mito-admin (in title, header, footer).

Login:

- [-] admin user and rights
  - [X] base mechanism: users, roles, DB migrations (imported from
    OpenBookStore, again. Contributions by gnuxie). &amp;lt;2024-07-31&amp;gt;
  - [X] templates
  - [ ] add access rights to all the admin dashboard routes
  - [ ] add user logout dropdown in app

Actions:

- [ ] in the list of records, have actions: export to CSV, etc.


More:

- reference documentation website and tutorial
- unit tests
- include static assets (Bulma…) to work offline

i18n

- translations. See cl-gettext in OpenBookStore.

style:

- [X] dark mode (thanks Bulma 1.0)
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>CLOS tutorial: I published 9 videos (1h 22min) on my course. You&#39;ll know enough to read the sources of Hunchentoot or the Kandria game 🎥 ⭐</title>
      <link>/blog/clos-tutorial-in-9-videos-1h22min--read-the-sources-of-hunchentoot-and-kandria/</link>
      <pubDate>Fri, 20 Dec 2024 18:01:14 +0100</pubDate>
      
      <guid>/blog/clos-tutorial-in-9-videos-1h22min--read-the-sources-of-hunchentoot-and-kandria/</guid>
      <description>

&lt;p&gt;This is a follow-up from &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1hh7bgm/clos_intro/&#34;&gt;yesterday&amp;rsquo;s post on reddit&lt;/a&gt; and an announce I wanted to make since this summer: &lt;strong&gt;I created 9 videos on CLOS, for a total of 1 hour and 22 minutes&lt;/strong&gt;, in which you learn what I detail below. You can &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISP-EVERYWHERE-2025&#34;&gt;watch the course and subscribe here (Christmas coupon)&lt;/a&gt; and &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;learn more on GitHub&lt;/a&gt;. The whole course is made of 51 videos divided in 9 chapters, for a total of 7 hours and 12 minutes. It is rated 4.71 / 5 as of date (thank you!!).&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://github.com/vindarel/common-lisp-course-in-videos/raw/master/announce.svg&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Yesterday was a great day because I received nice feedback:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is an amazing tutorial. What is really strange is I thought CLOS was complicated. I guess it can be but [Vincent] is amazing at explaining everything and demystifying it.&lt;/p&gt;

&lt;p&gt;   /u/intergalactic_llama&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🔥 I appreciate any (constructive ;) ) feedback and positive ones a lot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oh hey you made that tutorial. I started it but then got distracted by other stuff, been meaning to restart it and make my way through the whole thing. Really liked what I went through (I was on video 12 about redefining functions locally etc).&lt;/p&gt;

&lt;p&gt;   /u/runevault&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Look, other recent feedback on my course:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have done some preliminary Common Lisp exploration prior to this course but had a lot of questions regarding practical use and development workflows. This course was amazing for this! I learned a lot of useful techniques for actually writing the code in Emacs, as well as conversational explanations of concepts that had previously confused me in text-heavy resources. Please keep up the good work and continue with this line of topics, it is well worth the price!&lt;/p&gt;

&lt;p&gt;   Preston, October 2024&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&#34;&#34;&gt; &lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The instructor shows lots of tricks.&lt;/p&gt;

&lt;p&gt;   Tom, November 2024&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&#34;&#34;&gt; &lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Excellent selection of content. The delivery is not always obvious just for watching, but when I do the examples, it’s absolutely clear that what I need to be learning has been presented.&lt;/p&gt;

&lt;p&gt;   Steven, November 2024 &amp;lt;3&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-content&#34;&gt;Chapter content&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#1-defclass-make-instance-slots-aka-clos-crash-course-part-1-this-one-is-free-to-watch-🆓&#34;&gt;1. &lt;code&gt;defclass&lt;/code&gt;, &lt;code&gt;make-instance&lt;/code&gt;, &lt;code&gt;slots&lt;/code&gt;… aka CLOS crash course, part 1. This one is free to watch 🆓&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#1b-quizz-clos-crash-test&#34;&gt;1b. Quizz: CLOS crash test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#2-inheritance-multimethods-around-before-and-after-methods-aka-clos-crash-course-part-2&#34;&gt;2. Inheritance, multimethods, around, before and after methods… aka CLOS crash course, part 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#3-pretty-printing&#34;&gt;3. Pretty printing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#4-defclass-review&#34;&gt;4. &lt;code&gt;defclass&lt;/code&gt; review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#5-custom-constructors-and-custom-logic&#34;&gt;5. Custom constructors and custom logic.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#6-initialize-instance-control-if-and-how-any-objects-are-created&#34;&gt;6. &lt;code&gt;initialize-instance&lt;/code&gt;: control if and how any objects are created&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#7-multiple-inheritance&#34;&gt;7. Multiple inheritance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#8-defgeneric-vs-defmethod-when-to-use-which-which-is-better&#34;&gt;8. &lt;code&gt;defgeneric&lt;/code&gt; vs &lt;code&gt;defmethod&lt;/code&gt;: when to use which, which is better?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#8b-quizz-reading-code-from-real-world-projects&#34;&gt;8b. Quizz: reading code from real-world projects.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#9-class-allocation&#34;&gt;9. Class allocation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#outcome&#34;&gt;Outcome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-words&#34;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;chapter-content&#34;&gt;Chapter content&lt;/h1&gt;

&lt;h2 id=&#34;1-defclass-make-instance-slots-aka-clos-crash-course-part-1-this-one-is-free-to-watch&#34;&gt;1. &lt;code&gt;defclass&lt;/code&gt;, &lt;code&gt;make-instance&lt;/code&gt;, &lt;code&gt;slots&lt;/code&gt;… aka CLOS crash course, part 1. This one is free to watch 🆓&lt;/h2&gt;

&lt;p&gt;We see in more details: &lt;code&gt;defclass&lt;/code&gt;, &lt;code&gt;make-instance&lt;/code&gt;, attributes (aka slots), slot options (initarg, initform, reader, writer, accessor, documentation), slot-value, generic functions, &lt;code&gt;defmethod&lt;/code&gt;, &lt;strong&gt;dispatching&lt;/strong&gt; on built-in types, how objects are lazily updated, &lt;strong&gt;Slime inspector&lt;/strong&gt; actions, manipulating Slime &lt;strong&gt;presentations&lt;/strong&gt;, unbound slots and &lt;code&gt;slot-boundp&lt;/code&gt;, Slime shortcuts to create objects…&lt;/p&gt;

&lt;p&gt;We see a LOT already in this video, in an efficient way (way more
efficient than when I learned anyways), so if you&amp;rsquo;re on a budget you
can start with it (it&amp;rsquo;s free to watch) and complement with the
Cookbook, and the other free books. Also if you are a student shoot me
an email (and avoid the reddit chat, I don&amp;rsquo;t see the notifications, sorry
about that).&lt;/p&gt;

&lt;h2 id=&#34;1b-quizz-clos-crash-test&#34;&gt;1b. Quizz: CLOS crash test&lt;/h2&gt;

&lt;p&gt;There is a small quizz. Keep in mind that the Udemy plateform doesn&amp;rsquo;t support any Lisp language so I can&amp;rsquo;t put any live coding exercises, but we can read code.&lt;/p&gt;

&lt;h2 id=&#34;2-inheritance-multimethods-around-before-and-after-methods-aka-clos-crash-course-part-2&#34;&gt;2. Inheritance, multimethods, around, before and after methods… aka CLOS crash course, part 2&lt;/h2&gt;

&lt;p&gt;what we see more precisely: inheritance, multimethods, :around, :before and :after methods (think signals and overwriting default methods in other languages, that allow to control what happens when a method is called, if it is called at all), their order of execution, a Slime shortcut to export all symbols of a class at once…&lt;/p&gt;

&lt;h2 id=&#34;3-pretty-printing&#34;&gt;3. Pretty printing&lt;/h2&gt;

&lt;p&gt;We see how to change the default printed representation of objects.&lt;/p&gt;

&lt;p&gt;What we see: &lt;code&gt;print-object&lt;/code&gt;, with print-unreadable-object, the object type, the object identity, classic gotchas.&lt;/p&gt;

&lt;p&gt;You know, normally an object is printed un-readable as&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;ROBOT {1005CEBD03}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(guess what AOC day I am at)&lt;/p&gt;

&lt;p&gt;and we can use the &lt;code&gt;print-object&lt;/code&gt; &lt;em&gt;method&lt;/em&gt; to print it however we like, such as&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;ROBOT x: 47 y: 14 {1005CEBD03}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;4-defclass-review&#34;&gt;4. &lt;code&gt;defclass&lt;/code&gt; review&lt;/h2&gt;

&lt;p&gt;We give another pass, slower, to &lt;code&gt;defclass&lt;/code&gt;, slot options, &lt;code&gt;make-instance&lt;/code&gt;, and to the fact that &lt;strong&gt;accessors are generic functions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can skip this one if the crash course was crystal clear.&lt;/p&gt;

&lt;h2 id=&#34;5-custom-constructors-and-custom-logic&#34;&gt;5. Custom constructors and custom logic.&lt;/h2&gt;

&lt;p&gt;What we see: writing our own &amp;ldquo;make-person&amp;rdquo; terse constructor. Adding some logic before the object creation, doing side-effects after the object creation: towards &lt;code&gt;initialize-instance&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;6-initialize-instance-control-if-and-how-any-objects-are-created&#34;&gt;6. &lt;code&gt;initialize-instance&lt;/code&gt;: control if and how any objects are created&lt;/h2&gt;

&lt;p&gt;What we see: defining a &lt;code&gt;:before&lt;/code&gt; and an &lt;code&gt;:after&lt;/code&gt; method of &lt;code&gt;initialize-instance&lt;/code&gt; for our person class, in order to do the same logic than with our custom constructor, but with a built-in CL Object System mechanism. Note that using INITIALIZE-INSTANCE isn&amp;rsquo;t a must, only a &amp;ldquo;can&amp;rdquo;, that you can use for your own classes, or to control the creation of objects from other systems.&lt;/p&gt;

&lt;h2 id=&#34;7-multiple-inheritance&#34;&gt;7. Multiple inheritance&lt;/h2&gt;

&lt;p&gt;What we see: how to &lt;strong&gt;inherit&lt;/strong&gt; from multiple parent classes and who takes precedence, when the parents define the same slot with each a default value. Quick illustration. We use what is known as a &lt;strong&gt;mixin class&lt;/strong&gt; to add functionality to our class.&lt;/p&gt;

&lt;h2 id=&#34;8-defgeneric-vs-defmethod-when-to-use-which-which-is-better&#34;&gt;8. &lt;code&gt;defgeneric&lt;/code&gt; vs &lt;code&gt;defmethod&lt;/code&gt;: when to use which, which is better?&lt;/h2&gt;

&lt;p&gt;What we see: the use of &lt;code&gt;defgeneric&lt;/code&gt; and &lt;code&gt;defmethod&lt;/code&gt;, either separately, either together.
&lt;code&gt;defgeneric&lt;/code&gt; has a couple advantages in regards to documentation and keeping your code in sync with your image.&lt;/p&gt;

&lt;h2 id=&#34;9-class-allocation&#34;&gt;9. Class allocation&lt;/h2&gt;

&lt;p&gt;What we see: the default &lt;code&gt;:allocation :instance&lt;/code&gt; VS &lt;code&gt;:allocation :class&lt;/code&gt;. How to automatically count how many objects of a class are created.&lt;/p&gt;

&lt;h2 id=&#34;8b-quizz-reading-code-from-real-world-projects&#34;&gt;8b. Quizz: reading code from real-world projects.&lt;/h2&gt;

&lt;h1 id=&#34;outcome-of-the-chapter&#34;&gt;Outcome of the chapter&lt;/h1&gt;

&lt;p&gt;There was a lot of choices to make and advanced topics to ignore for
this first chapter on CLOS. What drove my choices was looking at
real-world code out there. As a result, by the end of this chapter,
you will &lt;strong&gt;know enough to read real-world Common Lisp projects&lt;/strong&gt; such
as the Hunchentoot &lt;strong&gt;web server&lt;/strong&gt; or &lt;a href=&#34;https://github.com/Shirakumo/kandria/&#34;&gt;the Kandria &lt;strong&gt;game&lt;/strong&gt;&lt;/a&gt;. Bravo!&lt;/p&gt;

&lt;h1 id=&#34;closing-words&#34;&gt;Closing words&lt;/h1&gt;

&lt;p&gt;First of all, thank you for your encouragements, and to everyone who
took the course or who shared it!&lt;/p&gt;

&lt;p&gt;Today I&amp;rsquo;d like to answer to my past me, a newcomer to Lisp on a
budget: why create a paying course? First of all, I still contribute
to the Cookbook, a collaborative resource. It&amp;rsquo;s not &amp;ldquo;free or paid&amp;rdquo;
resources, it&amp;rsquo;s both. Then, preparing and recording structured videos
takes so much time that I wouldn&amp;rsquo;t do this continuous effort if I hadn&amp;rsquo;t the
ambition to make a non-ridiculous hourly rate on them one
day. Disclaimer: it isn&amp;rsquo;t the case yet. Maybe next year, depending on
how many videos I release ;) I can pay my rent with them once every
few months though, that&amp;rsquo;s cool. Rest assured I&amp;rsquo;m not a
millionaire. I&amp;rsquo;m on my own projects and I don&amp;rsquo;t have a fixed (nor big)
income. So your contribution &lt;a href=&#34;https://github.com/sponsors/vindarel/&#34;&gt;or sponsorship&lt;/a&gt; counts,
if only for the good vibes that push me to spend more and more time on my
growing list of projects.&lt;/p&gt;

&lt;p&gt;&lt;!-- So, by the way, the CLOS chapter on the Cookbook is pretty complete IMO, it&#39;s only lacking advanced MOP. --&gt;&lt;/p&gt;

&lt;p&gt;You can sponsor &lt;a href=&#34;https://github.com/lisp-maintainers/lisp-maintainers&#34;&gt;other lispers&lt;/a&gt; too.&lt;/p&gt;

&lt;p&gt;Thank you and happy lisping.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Three web views for Common Lisp: build cross platform GUIs with Electron, WebUI or CLOG Frame</title>
      <link>/blog/three-web-views-for-common-lisp--cross-platform-guis/</link>
      <pubDate>Tue, 10 Dec 2024 10:59:06 +0100</pubDate>
      
      <guid>/blog/three-web-views-for-common-lisp--cross-platform-guis/</guid>
      <description>

&lt;p&gt;You dream to build a cross-platform GUI in Common Lisp? It&amp;rsquo;s now &lt;em&gt;easy&lt;/em&gt; with web views.&lt;/p&gt;

&lt;p&gt;Honestly GUIs are a difficult topic. Add in &amp;ldquo;cross platform&amp;rdquo; and you
can spend your life trying out different solutions and hesitating
between the best one for Common Lisp. It&amp;rsquo;s doable: Tk, Gtk3 and Gtk4,
Qt4 and Qt5, CAPI (LispWorks), IUP, Nuklear, Cocoa, McCLIM, Garnet,
Alloy, Java Swing… what can of worms do you want to open?&lt;/p&gt;

&lt;p&gt;The situation improved in the last years thanks to lispers writing new
bindings. So it&amp;rsquo;s possible you find one that works for your needs. That&amp;rsquo;s great, but
now: you have to learn the GUI framework :p&lt;/p&gt;

&lt;p&gt;If like me you already know the web, are developing a web app, and would like to ship
a desktop application, web views are making it easy. I know
the following ones, listed from least favourite to most favourite.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#electron&#34;&gt;Electron&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#ceramic-old-but-works&#34;&gt;Ceramic (old but works)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#electron-from-scratch&#34;&gt;Electron from scratch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#what-about-tauri&#34;&gt;What about Tauri?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#webui&#34;&gt;WebUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#clog-frame-webviewh-for-all&#34;&gt;CLOG Frame (webview.h for all)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;electron&#34;&gt;Electron&lt;/h1&gt;

&lt;p&gt;Electron is heavy, but really cross-platform, and it has many tools
around it. It allows to build releases for the three major OS from
your development machine, its ecosystem has tools to handle updates,
etc.&lt;/p&gt;

&lt;p&gt;Advise: study it before discarding it.&lt;/p&gt;

&lt;h2 id=&#34;ceramic-old-but-works&#34;&gt;Ceramic (old but works)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/ceramic/ceramic/&#34;&gt;Ceramic&lt;/a&gt; is a set of utilities
around Electron to help you build an Electron app: download the npm
packages, open a browser window, etc.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s its getting started snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Start the underlying Electron process
(ceramic:start)
;; ^^^^^ this here downloads ±200MB of node packages under the hood.

;; Create a browser window
(defvar window (ceramic:make-window :url &amp;quot;https://www.google.com/&amp;quot;
                                    :width 800
                                    :height 600))

;; Show it
(ceramic:show window)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you run &lt;code&gt;(ceramic:bundle :ceramic-hello-world)&lt;/code&gt; you get a .tar
file with your application, which you can distribute. Awesome!&lt;/p&gt;

&lt;p&gt;But what if you don&amp;rsquo;t want to redirect to google.com but open your own
app? You just build your web app in CL, run the webserver
(Hunchentoot, Clack…) on a given port, and you&amp;rsquo;ll open
&lt;code&gt;localhost:[PORT]&lt;/code&gt; in Ceramic/Electron. That&amp;rsquo;s it.&lt;/p&gt;

&lt;p&gt;Ceramic wasn&amp;rsquo;t updated in five years as of date and it downloads an
outdated version of Electron by default (see &lt;code&gt;(defparameter
*electron-version* &amp;quot;5.0.2&amp;quot;)&lt;/code&gt;), but you can change the version yourself.&lt;/p&gt;

&lt;p&gt;The new &lt;a href=&#34;https://github.com/neomacs-project/neomacs/&#34;&gt;Neomacs project, a structural editor and web browser&lt;/a&gt;, is a great modern example on how to use Ceramic. Give it a look and give it a try!&lt;/p&gt;

&lt;p&gt;What Ceramic actually does is abstracted away in the CL functions, so
I think it isn&amp;rsquo;t the best to start with. We can do without it to
understand the full process, here&amp;rsquo;s how.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ceramic API reference: &lt;a href=&#34;http://ceramic.github.io/docs/api-reference.html&#34;&gt;http://ceramic.github.io/docs/api-reference.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;electron-from-scratch&#34;&gt;Electron from scratch&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s our web app embedded in Electron:&lt;/p&gt;



&lt;img src=&#34;https://media2.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqjy44zgpae1jp5vkxwx.png&#34; style=&#34;&#34; alt=&#34;&#34;/&gt;



&lt;p&gt;Our steps are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;follow the Electron installation instructions,&lt;/li&gt;
&lt;li&gt;build a binary of your Lisp web app, including assets and HTML templates, if any.

&lt;ul&gt;
&lt;li&gt;see this post: &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/&#34;&gt;https://lisp-journey.gitlab.io/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/&lt;/a&gt; (the process will be a tad simpler without Djula templates)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;bundle this binary into the final Electron build.&lt;/li&gt;
&lt;li&gt;and that&amp;rsquo;s it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also run the Lisp web app from sources, of course, without
building a binary, but then you&amp;rsquo;ll have to ship all the lisp sources.&lt;/p&gt;

&lt;!-- You can also have a look at --&gt;

&lt;!-- https://github.com/mikelevins/electron-lisp-boilerplate for this, --&gt;

&lt;!-- their main.js has the pattern, using child_process. --&gt;

&lt;h3 id=&#34;main-js&#34;&gt;main.js&lt;/h3&gt;

&lt;p&gt;The most important file to an Electron app is the main.js. The one we show below does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it starts Electron&lt;/li&gt;
&lt;li&gt;it starts our web application on the side, as a child process, from a binary name, and a port.&lt;/li&gt;
&lt;li&gt;it shows our child process&amp;rsquo; stdout and stderr&lt;/li&gt;
&lt;li&gt;it opens a browser window to show our app, running on localhost.&lt;/li&gt;
&lt;li&gt;it handles the close event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;rsquo;s our version.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-javascript&#34;&gt;console.log(`Hello from Electron 👋`)

const { app, BrowserWindow } = require(&#39;electron&#39;)

const { spawn } = require(&#39;child_process&#39;);

// FIXME Suppose we have our app binary at the current directory.

// FIXME This is our hard-coded binary name.
var binaryPaths = [
    &amp;quot;./openbookstore&amp;quot;,
];

// FIXME Define any arg required for the binary.
// This is very specific to the one I built for the example.
var binaryArgs = [&amp;quot;--web&amp;quot;];

const binaryapp = null;

const runLocalApp = () =&amp;gt; {
    &amp;quot;Run our binary app locally.&amp;quot;
    console.log(&amp;quot;running our app locally…&amp;quot;);
    const binaryapp = spawn(binaryPaths[0], binaryArgs);
    return binaryapp;
}

// Start an Electron window.

const createWindow = () =&amp;gt; {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
  })

  // Open localhost on the app&#39;s port.
  // TODO: we should read the port from an environment variable or a config file.
  // FIXME hard-coded PORT number.
  win.loadURL(&#39;http://localhost:4242/&#39;)
}

// Run our app.
let child = runLocalApp();

// We want to see stdout and stderr of the child process
// (to see our Lisp app output).
child.stdout.on(&#39;data&#39;, (data) =&amp;gt; {
  console.log(`stdout:\n${data}`);
});

child.stderr.on(&#39;data&#39;, (data) =&amp;gt; {
  console.error(`stderr: ${data}`);
});

child.on(&#39;error&#39;, (error) =&amp;gt; {
  console.error(`error: ${error.message}`);
});

// Handle Electron close events.
child.on(&#39;close&#39;, (code) =&amp;gt; {
  console.log(`openbookstore process exited with code ${code}`);
});

// Open it in Electron.
app.whenReady().then(() =&amp;gt; {
    createWindow();

    // Open a window if none are open (macOS)
    if (process.platform == &#39;darwin&#39;) {
        app.on(&#39;activate&#39;, () =&amp;gt; {
            if (BrowserWindow.getAllWindows().length === 0) createWindow()
        })
    }
})


// On Linux and Windows, quit the app main all windows are closed.
app.on(&#39;window-all-closed&#39;, () =&amp;gt; {
    if (process.platform !== &#39;darwin&#39;) {
        app.quit();
    }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run it with &lt;code&gt;npm run start&lt;/code&gt; (you also have an appropriate packages.json), this gets you the previous screenshot.&lt;/p&gt;

&lt;p&gt;JS and Electron experts, please criticize and build on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing parts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We didn&amp;rsquo;t fully finish the example: we need to automatically bundle
the binary into the Electron release.&lt;/p&gt;

&lt;p&gt;Then, if you want to communicate from the Lisp app to the Electron
window, and the other way around, you&amp;rsquo;ll have to use the JavaScript layers. Ceramic might help here.&lt;/p&gt;

&lt;p&gt;(this section was first released here: &lt;a href=&#34;https://dev.to/vindarel/common-lisp-gui-with-electron-how-to-28fj&#34;&gt;https://dev.to/vindarel/common-lisp-gui-with-electron-how-to-28fj&lt;/a&gt;)&lt;/p&gt;

&lt;h2 id=&#34;what-about-tauri&#34;&gt;What about Tauri?&lt;/h2&gt;

&lt;p&gt;Bundling an app with &lt;a href=&#34;https://tauri.app/&#34;&gt;Tauri&lt;/a&gt; will, AFAIK (I just
tried quickly), involve the same steps than with Electron. Tauri might
still have less tools for it.&lt;/p&gt;

&lt;h1 id=&#34;webui&#34;&gt;WebUI&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/webui-dev/webui/&#34;&gt;WebUI&lt;/a&gt; is a new kid in town. It is in development, it has bugs. You can view it as a wrapper around a browser window (or webview.h).&lt;/p&gt;

&lt;p&gt;However it is ligthweight, it is &lt;em&gt;easy to build&lt;/em&gt; and we have Lisp bindings.&lt;/p&gt;

&lt;p&gt;A few more words about it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use any web browser or WebView as GUI, with your preferred language in the backend and modern web technologies in the frontend, all in a lightweight portable library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;written in pure C&lt;/li&gt;
&lt;li&gt;one header file&lt;/li&gt;
&lt;li&gt;multi-platform &amp;amp; multi-browser&lt;/li&gt;
&lt;li&gt;cross-platform webview&lt;/li&gt;
&lt;li&gt;we can call JS from Common Lisp, and call Common Lisp from JS.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Think of WebUI like a WebView controller, but instead of embedding the WebView controller in your program, which makes the final program big in size, and non-portable as it needs the WebView runtimes. Instead, by using WebUI, you use a tiny static/dynamic library to run any installed web browser and use it as GUI, which makes your program small, fast, and portable. All it needs is a web browser.&lt;/p&gt;

&lt;p&gt;your program will always run on all machines, as all it needs is an installed web browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds compelling right?&lt;/p&gt;

&lt;p&gt;The other good news is that Common Lisp was one of the first languages
it got bindings for. How it happened: I was chating in Discord, mentioned WebUI and BAM! @garlic0x1 developed bindings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/garlic0x1/cl-webui/&#34;&gt;https://github.com/garlic0x1/cl-webui/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;thank you so much! (@garlic0x1 has more cool projects on GitHub you can browse. He&amp;rsquo;s also a contributor to Lem)&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a simple snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defpackage :webui/examples/minimal
  (:use :cl :webui)
  (:export :run))
(in-package :webui/examples/minimal)

(defun run ()
  (let ((w (webui-new-window)))
    (webui-show w &amp;quot;&amp;lt;html&amp;gt;Hello, world!&amp;lt;/html&amp;gt;&amp;quot;)
    (webui-wait)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I would be the happiest lisper in the world if I didn&amp;rsquo;t have an annoying issue. See &lt;a href=&#34;https://github.com/garlic0x1/cl-webui/issues/1&#34;&gt;#1&lt;/a&gt;. I can run my example just fine, but nothing happens the second time :/ I don&amp;rsquo;t know if it&amp;rsquo;s a WebUI thing, the bindings, my system, my build of WebUI… so I&amp;rsquo;ll give this more time.&lt;/p&gt;

&lt;p&gt;Fortunately though, the third solution of this blog post is my favourite! o/&lt;/p&gt;

&lt;h1 id=&#34;clog-frame-webview-h-for-all&#34;&gt;CLOG Frame (webview.h for all)&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/rabbibotton/clog/tree/main/clogframe&#34;&gt;CLOG Frame&lt;/a&gt;
is part of the CLOG framework. However, it is &lt;em&gt;not&lt;/em&gt; tied to CLOG… nor
to Common Lisp!&lt;/p&gt;

&lt;p&gt;CLOG Frame is a short C++ program that builds an executable that takes
an URL and a PORT as CLI parameters and opens a &lt;a href=&#34;https://github.com/webview/webview&#34;&gt;webview.h&lt;/a&gt; window.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s easy to build and works just fine.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a great approach. We don&amp;rsquo;t need to develop CFFI bindings for
webview.h. However such bindings would still be nice to have. I did a
cursory search and didn&amp;rsquo;t find a project that seems to work. But
please don&amp;rsquo;t take my word on it. Do you want to try &lt;a href=&#34;https://github.com/webview/webview&#34;&gt;this latest
cl-webview&lt;/a&gt;, or have a go at the bindings?&lt;/p&gt;

&lt;p&gt;Back to our matter.&lt;/p&gt;

&lt;p&gt;This is CLOG Frame: 20 lines!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-C&#34;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;sstream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;quot;webview.h&amp;quot;

int main(int argc,char* argv[]) {
  webview::webview w(true, nullptr);
  webview::webview *w2 = &amp;amp;w;
  w.set_title(argv[1]);
  w.set_size(std::stoi(argv[3]), std::stoi(argv[4]), WEBVIEW_HINT_NONE);
  w.bind(&amp;quot;clogframe_quit&amp;quot;, [w2](std::string s) -&amp;gt; std::string {
    w2-&amp;gt;terminate();
    return &amp;quot;&amp;quot;;
  });
  std::ostringstream o;
  o &amp;lt;&amp;lt; &amp;quot;http://127.0.0.1:&amp;quot; &amp;lt;&amp;lt; argv[2];
  w.navigate(o.str());
  w.run();
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Compile it on GNU/Linux like this and don&amp;rsquo;t you worry, it takes a fraction of a second:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;c++ clogframe.cpp -ldl `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0` -o clogframe
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(see its repo for other platforms)&lt;/p&gt;

&lt;p&gt;this gives you a &lt;code&gt;clogframe&lt;/code&gt; binary. Put it in your $PATH or remember its location. It&amp;rsquo;s just a short C++ binary, so it weights 197Kb.&lt;/p&gt;

&lt;p&gt;Now, back to your web app that you wrote in Common Lisp and that is
waiting to be shipped to users.&lt;/p&gt;

&lt;p&gt;Start your web app. Say it is started on port 4284.&lt;/p&gt;

&lt;p&gt;From the Lisp side, open a CLOG Frame window like this&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(uiop:launch-program (list &amp;quot;./clogframe&amp;quot;
                           &amp;quot;Admin&amp;quot;
                           (format nil &amp;quot;~A/admin/&amp;quot; 4284)
                           ;; window dimensions (strings)
                           &amp;quot;1280&amp;quot; &amp;quot;840&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and voilà.&lt;/p&gt;



&lt;img src=&#34;/images/clogframe-on-top-emacs.png&#34; style=&#34;max-width: 100%;&#34; alt=&#34;A CLOG Frame window showing a WIP Common Lisp web app on top of Emacs.&#34;/&gt;



&lt;p&gt;Now for the cross-platform part, you&amp;rsquo;ll need to build clogframe and
your web app on the target OS (like with any CL app). Webview.h is cross-platform.
Leave us a comment when you have a good CI setup for the three main OSes (I am studying &lt;a href=&#34;https://github.com/40ants/ci/&#34;&gt;40ants/ci&lt;/a&gt; and &lt;a href=&#34;https://github.com/melusina-org/make-common-lisp-program/&#34;&gt;make-common-lisp-program&lt;/a&gt; for now).&lt;/p&gt;

&lt;p&gt;CLOG Frame should be a (popular) project on its own IMO! (@dbotton might make it independant eventually)&lt;/p&gt;

&lt;p&gt;Please share any experience you might have on the topic 👍&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>cl-ansi-term: print tables with style, and other script utilities</title>
      <link>/blog/cl-ansi-term--print-tables-with-style-and-other-script-utilities/</link>
      <pubDate>Fri, 22 Nov 2024 11:56:40 +0100</pubDate>
      
      <guid>/blog/cl-ansi-term--print-tables-with-style-and-other-script-utilities/</guid>
      <description>

&lt;p&gt;I am not the original author of
&lt;a href=&#34;https://github.com/vindarel/cl-ansi-term&#34;&gt;cl-ansi-term&lt;/a&gt;, but I
revived it lately. In particular, I added useful stuff to print data
in tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;print list of lists (where the first one is the list of headers)&lt;/li&gt;
&lt;li&gt;print &lt;strong&gt;horizontal&lt;/strong&gt; or &lt;strong&gt;vertical tables&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;the header keys are either the first row, either the first column&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;print &lt;strong&gt;hash-tables, plists, alists&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;filter keys to display&lt;/strong&gt; (include, exclude)&lt;/li&gt;
&lt;li&gt;limit the number of columns&lt;/li&gt;
&lt;li&gt;they can be &lt;strong&gt;styled&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;with or without borders&lt;/li&gt;
&lt;li&gt;choose the columns&amp;rsquo; width&lt;/li&gt;
&lt;li&gt;choose the borders&amp;rsquo; elements (&amp;ldquo;-|+&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;choose the headers&amp;rsquo; and the cells&amp;rsquo; style (color, bold…).&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(progn
  (defparameter d (serapeum:dict :a 1.1 :b 2.2 :c 3.3))

  (banner &amp;quot;A single hash-table&amp;quot;)
  (table d)

  (banner &amp;quot;A single hash-table, in columns&amp;quot;)
  (vtable d)

  (banner &amp;quot;A single hash-table, ignoring column :B&amp;quot;)
  (table d :exclude :b)

  (banner &amp;quot;A single hash-table, vertically ignoring column :B&amp;quot;)
  (vtable d :exclude :b)

  (banner &amp;quot;A list of hash-tables&amp;quot;)
  (table (list d d d))

  (banner &amp;quot;A list of hash-tables, ignoring column :B&amp;quot;)
  (table (list d d d) :keys &#39;(:a :c))

  (banner &amp;quot;A list of hash-tables, in columns&amp;quot;)
  (vtable (list d d d))

  (banner &amp;quot;same, ignoring the column :b&amp;quot;)
  (vtable (list d d d) :exclude :b))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;prints:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;--------------------------------------------------------------------------------
     A single hash-table
--------------------------------------------------------------------------------


+---------+---------+---------+
|A        |B        |C        |
+---------+---------+---------+
|1.1      |2.2      |3.3      |
+---------+---------+---------+

--------------------------------------------------------------------------------
     A single hash-table, in columns
--------------------------------------------------------------------------------


+---------+---------+
|A        |1.1      |
+---------+---------+
|B        |2.2      |
+---------+---------+
|C        |3.3      |
+---------+---------+

--------------------------------------------------------------------------------
     A single hash-table, ignoring column :B
--------------------------------------------------------------------------------


+---------+---------+
|A        |C        |
+---------+---------+
|1.1      |3.3      |
+---------+---------+

--------------------------------------------------------------------------------
     A single hash-table, vertically ignoring column :B
--------------------------------------------------------------------------------


+---------+---------+
|A        |1.1      |
+---------+---------+
|C        |3.3      |
+---------+---------+

--------------------------------------------------------------------------------
     A list of hash-tables
--------------------------------------------------------------------------------


+---------+---------+---------+
|A        |B        |C        |
+---------+---------+---------+
|1.1      |2.2      |3.3      |
+---------+---------+---------+
|1.1      |2.2      |3.3      |
+---------+---------+---------+
|1.1      |2.2      |3.3      |
+---------+---------+---------+

--------------------------------------------------------------------------------
     A list of hash-tables, ignoring column :B
--------------------------------------------------------------------------------


+---------+---------+
|A        |C        |
+---------+---------+
|1.1      |3.3      |
+---------+---------+
|1.1      |3.3      |
+---------+---------+
|1.1      |3.3      |
+---------+---------+

--------------------------------------------------------------------------------
     A list of hash-tables, in columns
--------------------------------------------------------------------------------


+---------+---------+---------+---------+
|A        |1.1      |1.1      |1.1      |
+---------+---------+---------+---------+
|B        |2.2      |2.2      |2.2      |
+---------+---------+---------+---------+
|C        |3.3      |3.3      |3.3      |
+---------+---------+---------+---------+

--------------------------------------------------------------------------------
     same, ignoring the column :b
--------------------------------------------------------------------------------


+---------+---------+---------+---------+
|A        |1.1      |1.1      |1.1      |
+---------+---------+---------+---------+
|C        |3.3      |3.3      |3.3      |
+---------+---------+---------+---------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or again&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;TERM&amp;gt; (table (list d d d) :exclude :b  :border-style nil)
A         C
1.1       3.3
1.1       3.3
1.1       3.3
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;real-example&#34;&gt;Real example&lt;/h2&gt;

&lt;p&gt;Remember, &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/running-my-4th-lisp-script-in-production/&#34;&gt;the scripts I use in production&lt;/a&gt;.
I&amp;rsquo;m usually fine with big data output in the REPL, until:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;until I want a cleaner output in the production script, so I can see
quicker what&amp;rsquo;s going on.&lt;/li&gt;
&lt;li&gt;when I want to filter and study the data a bit more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case I extract data from my DB and I get a list of plists:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;((:|isbn| &amp;quot;3760281971082&amp;quot; :|quantity| -1 :|price| 12.8d0 :|vat| NIL
  :|distributor| NIL :|discount| NIL :|type_name| NIL :|type_vat| NIL
  :|price_bought| NIL :|price_sold| 12.8d0 :|quantity_sold| 1 :|sold_date|
  &amp;quot;2024-04-03 09:27:12&amp;quot;)
 (:|isbn| &amp;quot;9791094298169&amp;quot; :|quantity| 4 :|price| 15.0d0 :|vat| NIL
  :|distributor| NIL :|discount| NIL :|type_name| &amp;quot;book&amp;quot; :|type_vat| NIL
  :|price_bought| NIL :|price_sold| 15.0d0 :|quantity_sold| 1 :|sold_date|
  &amp;quot;2024-04-03 10:06:58&amp;quot;)
 …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the &lt;code&gt;table&lt;/code&gt; and &lt;code&gt;vtable&lt;/code&gt; functions, I can explore data in a clearer fashion.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(uiop:add-package-local-nickname :sera :serapeum)
(term:table (sera:take 15 *sells*)
                          :keys &#39;(:|isbn| :|quantity| :|price|)
                          :plist t
                          :column-width &#39;(15 10 10))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;+--------------+---------+---------+
|isbn          |quantity |price    |
+--------------+---------+---------+
|3760281971082 |-1       |12.8d0   |
+--------------+---------+---------+
|9791094298169 |4        |15.0d0   |
+--------------+---------+---------+
|3700275724249 |-126     |2.8d0    |
+--------------+---------+---------+
|9782372600842 |1        |10.0d0   |
+--------------+---------+---------+
|9782372600736 |0        |10.0d0   |
+--------------+---------+---------+
|9782221256770 |1        |19.0d0   |
+--------------+---------+---------+
|3700275734392 |171      |3.95d0   |
+--------------+---------+---------+
|3662846007789 |2        |16.95d0  |
+--------------+---------+---------+
|9782368292907 |1        |8.95d0   |
+--------------+---------+---------+
|9782095022679 |1        |12.95d0  |
+--------------+---------+---------+
|3662846007871 |5        |5.9d0    |
+--------------+---------+---------+
|9782092588949 |2        |5.95d0   |
+--------------+---------+---------+
|3700275724249 |-126     |2.8d0    |
+--------------+---------+---------+
|3700275734392 |171      |3.95d0   |
+--------------+---------+---------+
|3770017095135 |0        |29.99d0  |
+--------------+---------+---------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, this calls for more features: align the numbers, automatically adapt the cells&amp;rsquo; width (DONE), style cells individually (DONE), etc.&lt;/p&gt;

&lt;p&gt;(I&amp;rsquo;m sure we could have an explorer window, watching for changes,
displaying data in a real table with interactive features… I can feel
we&amp;rsquo;re close… CLOG frame and malleable systems someone?)&lt;/p&gt;

&lt;h2 id=&#34;use-case-and-other-primitives-title-banner-vspace-o-list&#34;&gt;Use case and other primitives: title, banner, vspace, o-list&lt;/h2&gt;

&lt;p&gt;The use case is cleaner output for scripts.&lt;/p&gt;

&lt;p&gt;Other libraries exist with other goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/AccelerationNet/data-table&#34;&gt;https://github.com/AccelerationNet/data-table&lt;/a&gt; &amp;ldquo;A Common Lisp data structure representing tabular data (think CSVs and database results)&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/teddy&#34;&gt;https://github.com/40ants/teddy&lt;/a&gt; &amp;ldquo;A data framework for Common Lisp&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/telephil/cl-ascii-table/&#34;&gt;https://github.com/telephil/cl-ascii-table/&lt;/a&gt; &amp;ldquo;Common Lisp API to present tabular data in ASCII-art tables&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some of other cl-ansi-term&amp;rsquo;s utilities:&lt;/p&gt;

&lt;p&gt;ordered and un-ordered lists:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(term:o-list &#39;((:one one-a (:one-b :one-b-1 :one-b-2)) :two))
1. ONE
   1. ONE-A
   2. ONE-B
      1. ONE-B-1
      2. ONE-B-2
2. TWO
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Horizontal lines&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(term:hr :filler &amp;quot;=&amp;quot;)
================================================================================
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;printing stuff, align on screen:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(term:cat-print &#39;(:abc :def :ghi) :align :center)
;; =&amp;gt;

                                   ABCDEFGHI
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;vspace&lt;/code&gt; for vertical space (default: 3 newlines)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;banner&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(banner &amp;quot;My title&amp;quot; :space 1)

--------------------------------------------------------------------------------
     My title
--------------------------------------------------------------------------------


&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;stylesheets-and-colorized-text&#34;&gt;Stylesheets and colorized text&lt;/h3&gt;

&lt;p&gt;The library allows to use styles.&lt;/p&gt;

&lt;p&gt;Start by defining your stylesheet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(term:update-style-sheet
 &#39;((:header :cyan   :underline)
   (:mark   :red    :reverse)
   (:term   :yellow :bold)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;:header&lt;/code&gt;, &lt;code&gt;:mark&lt;/code&gt; and &lt;code&gt;:term&lt;/code&gt; are now your own vocabulary. Anytime you
use functions that accept a style, reference them.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(term:table (list &#39;(:name :age) &#39;(:me 7)) :header-style :header)
&lt;/code&gt;&lt;/pre&gt;



&lt;img src=&#34;/images/ansi-term-table-color.png&#34; style=&#34;max-height: 100%;&#34; alt=&#34;data printed in tables, with colors.&#34;/&gt;



&lt;p&gt;To see colors in a &amp;ldquo;dumb&amp;rdquo; terminal like in Emacs Slime, install the package &lt;a href=&#34;https://melpa.org/#/slime-repl-ansi-color&#34;&gt;&lt;code&gt;slime-repl-ansi-color&lt;/code&gt;&lt;/a&gt;, &amp;ldquo;require&amp;rdquo; it and enable it ith &lt;code&gt;M-x slime-repl-ansi-color-mode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also disable styles in non-interactive terminals with &lt;code&gt;term::*enable-effects-on-dumb-terminals*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Happy lisping.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Running my 4th Common Lisp script in production© - you can do it too</title>
      <link>/blog/running-my-4th-lisp-script-in-production/</link>
      <pubDate>Tue, 22 Oct 2024 19:19:26 +0200</pubDate>
      
      <guid>/blog/running-my-4th-lisp-script-in-production/</guid>
      <description>

&lt;!-- 
 --&gt;
&lt;!-- &lt;img src=&#34;http://abstock.org/cat-shelf-thumb.jpg&#34; style=&#34;border-radius: 50%; max-height: 300px; &#34; alt=&#34;A cat on a bookshelf. Image Adam Ramirez&#34;/&gt; --&gt;
&lt;!-- 
 --&gt;

&lt;p&gt;Last week I finished a new service written in Common Lisp. It now runs
in production© every mornings, and it expands the set of services I
offer to clients.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s the 4th service of this kind that I developed:
- they are not big - but &lt;strong&gt;have to be done&lt;/strong&gt; nonetheless, and &lt;strong&gt;the quicker
the better&lt;/strong&gt; (they each amount to 1k to 2k lines of Lisp code),
- they are not part of a super advanced domain that requires Common
Lisp superpowers - &lt;strong&gt;I am the one who benefits from CL&lt;/strong&gt; during
development,
- I could have written them in Python - and conversely &lt;strong&gt;nothing
prevented me from writing them in Common Lisp&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So here lies the goal of this post: illustrate that you don&amp;rsquo;t need to
need a super difficult problem to use Common Lisp. This has been asked
many times, directly to me or on social media :)&lt;/p&gt;

&lt;p&gt;At the same time, I want to encourage you to write a little something
about how you use Common Lisp in the real world. &lt;strong&gt;Sharing creates
emulation. Do it!&lt;/strong&gt; If you don&amp;rsquo;t have a blog you can simply write in a
new GitHub repository or in a Gist and come share on /r/lisp. We don&amp;rsquo;t care. Thanks &amp;lt;3&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll briefly see what my scripts do, what libraries I use, how I deploy them, what I did along the way.&lt;/p&gt;

&lt;p&gt;Needless to say that I dogfooded my &lt;a href=&#34;http://ciel-lang.org/&#34;&gt;CIEL&lt;/a&gt; (beta) meta-library and scripting tool for all those projects.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#scripts-n4-and-2---shaping-and-sending-data---when-you-can-write-lisp-on-the-side&#34;&gt;Scripts n°4 and 2 - shaping and sending data - when you can write Lisp on the side&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#sftp&#34;&gt;SFTP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deploying&#34;&gt;Deploying&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#script-n2-and-simple-ftp&#34;&gt;Script n°2 and simple FTP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#scripts-n3-and-1---complementary-web-apps&#34;&gt;Scripts n°3 and 1 - complementary web apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#lasting-words&#34;&gt;Lasting words&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#links&#34;&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;scripts-n-4-and-2-shaping-and-sending-data-when-you-can-write-lisp-on-the-side&#34;&gt;Scripts n°4 and 2 - shaping and sending data - when you can write Lisp on the side&lt;/h1&gt;

&lt;p&gt;My latest script needs to read data from a DB, format what&amp;rsquo;s necessary
according to specifications, and send the result by SFTP.&lt;/p&gt;

&lt;p&gt;In this case I read a DB that I own, created by a software that I
develop and host. So I could have developed this script in the
software itself, right? I could have, but I would have been tied to
the main project&amp;rsquo;s versioning scheme, quirks, and deployment. I rather
had to write this script on the side. And &lt;em&gt;since it can be done on the
side, it can be done in Common Lisp&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have to extract products and their data (price, VAT…), aggregate the
numbers for each day, write this to a file, according to a
specification.&lt;/p&gt;



&lt;img src=&#34;/images/spec1.png&#34; style=&#34;max-width: 100%&#34; alt=&#34;Extract of my specification document.&#34;/&gt;



&lt;p&gt;To read the DB, I used &lt;code&gt;cl-dbi&lt;/code&gt;. I didn&amp;rsquo;t format the SQL with SxQL
this time  like in my web apps (where I use the Mito light ORM), but I wrote SQL directly. I&amp;rsquo;m spoiled by the Django ORM
(which has its idiosyncrasies and shortcomings), so I double checked
the different kinds of JOINs and all went well.&lt;/p&gt;

&lt;p&gt;I had to group rows by some properties, so it was a great time to use &lt;code&gt;serapeum:assort&lt;/code&gt;. I left you an example here: &lt;a href=&#34;https://dev.to/vindarel/common-lisps-group-by-is-serapeumassort-32ma&#34;&gt;https://dev.to/vindarel/common-lisps-group-by-is-serapeumassort-32ma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dates have to be handled in different formats. I used &lt;code&gt;local-time&lt;/code&gt; of
course, and I still greatly appreciate its lispy formatter syntax:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun date-yymmddhhnnss (&amp;amp;optional date stream)
  (local-time:format-timestring stream
                                (or date (local-time:now))
                                :format
                                &#39;((:year 4)
                                  (:month 2)
                                  (:day 2)
                                  (:hour 2)
                                  (:min 2)
                                  (:sec 2)
                                  )))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the 2 in &lt;code&gt;(:month 2)&lt;/code&gt; is to ensure the month is written with 2 digits.&lt;/p&gt;

&lt;p&gt;Once the file is written, I have to send it to a SFTP server, with the client&amp;rsquo;s codes.&lt;/p&gt;

&lt;p&gt;I wrote a &lt;code&gt;profile&lt;/code&gt; class to encapsulate the client&amp;rsquo;s data as well as
some functions to read the credentials from either environment
variables, the file system, or a lisp variable. I had a top-level
profile object for ease of testing, but I made sure that my functions
formatting or sending data required a &lt;code&gt;profile&lt;/code&gt; parameter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun send-stock (profile &amp;amp;key date) …)
(defun write-stock (profile filename) …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Still nothing surprising, but it&amp;rsquo;s tempting to only use global
parameters for a one-off script. Except the program grows and you pay
the mess later.&lt;/p&gt;

&lt;h2 id=&#34;sftp&#34;&gt;SFTP&lt;/h2&gt;

&lt;p&gt;To send the result through SFTP, I had to make a choice. The SFTP
command line doesn&amp;rsquo;t make it possible to give a password as argument
(or via an environment variable, etc). So I use &lt;code&gt;lftp&lt;/code&gt; (in Debian
repositories) that allows to do that. In the end, we format a command
like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;lftp sftp://user:****@host  -e &amp;quot;CD I/; put local-file.name; bye&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can format the command string and run it with &lt;code&gt;uiop:run-program&lt;/code&gt;:
no problem, but I took the opportunity to release another utility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/lftp-wrapper&#34;&gt;https://github.com/vindarel/lftp-wrapper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, you create a &lt;code&gt;profile&lt;/code&gt; object. This one-liner reads the
credentials from a lispy file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar profile (make-profile-from-plist (uiop:read-file-form &amp;quot;CREDS.lisp-expr&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then you define the commands you&amp;rsquo;ll want to run:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar command (put :cd &amp;quot;I/&amp;quot; :local-filename &amp;quot;data.csv&amp;quot;))
;; #&amp;lt;PUT cd: &amp;quot;I/&amp;quot;, filename: &amp;quot;data.csv&amp;quot; {1007153883}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and finally you call the &lt;code&gt;run&lt;/code&gt; method on a profile and a command. Tada.&lt;/p&gt;

&lt;h2 id=&#34;deploying&#34;&gt;Deploying&lt;/h2&gt;

&lt;p&gt;Build a binary the classic way (it&amp;rsquo;s all on the Cookbook), send it to your server, run it.&lt;/p&gt;

&lt;p&gt;(during a testing phase I have deployed &amp;ldquo;as a script&amp;rdquo;, from sources, which is a bit quicker to pull changes and try again on the server)&lt;/p&gt;

&lt;p&gt;Set up a CRON job.&lt;/p&gt;

&lt;p&gt;No Python virtual env to activate in the CRON environment…&lt;/p&gt;

&lt;p&gt;Add command line arguments the easy way or with the library of your
choice (I like Clingon).&lt;/p&gt;

&lt;h2 id=&#34;script-n-2-and-simple-ftp&#34;&gt;Script n°2 and simple FTP&lt;/h2&gt;

&lt;p&gt;My script #2 at the time was similar and simpler. I extract the same products
but only take their quantities, and I assemble lines like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;EXTRACTION STOCK DU 11/04/2008
....978202019116600010000001387
....978270730656200040000000991
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For this service, we have to send the file to a simple FTP server.&lt;/p&gt;

&lt;p&gt;We have a pure Lisp library for FTP (and not SFTP) which works very
well, &lt;a href=&#34;https://github.com/pinterface/cl-ftp&#34;&gt;cl-ftp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a typical example of an old library that didn&amp;rsquo;t receive any
update in years and so that looks abandoned, that has seldom
documentation but whose usage is easy to infer, and that does its job
as requested.&lt;/p&gt;

&lt;p&gt;For example we do this to send a file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ftp:with-ftp-connection (conn :hostname hostname
                                   :username username
                                   :password password
                                   :passive-ftp-p t)
      (ftp:store-file conn local-filename filename))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I left you notes about cl-ftp and my SFTP wrapper here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/vindarel/ftp-and-sftp-clients-for-common-lisp-1c3b&#34;&gt;https://dev.to/vindarel/ftp-and-sftp-clients-for-common-lisp-1c3b&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;scripts-n-3-and-n-1-specialized-web-apps&#34;&gt;Scripts n°3 and n°1 - specialized web apps&lt;/h1&gt;

&lt;p&gt;A recent web app that I&amp;rsquo;m testing with a couple clients extends an
existing stock management system.&lt;/p&gt;

&lt;p&gt;This one also was done in order to avoid a Python monolith. I still
needed additions in the Python main software, but this little app can
be independent and grow on its own. The app maintains its state and
communicates it with a REST API.&lt;/p&gt;



&lt;img title=&#34;Searching for books and adding them to carts.&#34; src=&#34;/images/cmdcoll-search-lisp.png&#34; style=&#34;max-width: 100%&#34; alt=&#34;Searching books in my little web app.&#34;/&gt;



&lt;p&gt; &lt;/p&gt;



&lt;img title=&#34;Reviewing one&#39;s cart. It&#39;s all Common Lisp and clients don&#39;t care. They speak about CSS. Sometimes.&#34; src=&#34;/images/cmdcoll-exple.png&#34; style=&#34;max-width: 100%&#34; alt=&#34;Another web app example used by clients strangers to Lisp.&#34;/&gt;



&lt;p&gt;It gives a web interface to their clients (so my clients&amp;rsquo; clients, but
not all of them, only the institutional) so that they can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;search for products&lt;/li&gt;
&lt;li&gt;add them in shopping carts&lt;/li&gt;
&lt;li&gt;validate the cart, which sends the data to the main software and notifies the owner, who will work on them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The peculiarities of this app are that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there is no user login, we use unique URLs with UUIDs in the form: &lt;code&gt;http://command.client.com/admin-E9DFOO82-R2D2-007/list?id=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;I need a bit of file persistence but I didn&amp;rsquo;t want the rigidity of a
database so I am using the &lt;a href=&#34;https://github.com/html/clache&#34;&gt;clache&lt;/a&gt;
library. Here also, not a great activity, but it works©. I persist lists and hash-tables. Now that the needs grow and the original scope doesn&amp;rsquo;t cut it any more, I wonder how long I&amp;rsquo;ll survive without a DB. Only for its short SQL queries VS lisp code to filter data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I deploy a &lt;strong&gt;self-contained binary: code + html templates&lt;/strong&gt; in the same binary (+ the implementation, the web server, the debugger…), with Systemd.&lt;/p&gt;

&lt;p&gt;I wrote more on how to ship a standalone binary with templates and static assets with Djula templates here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/&#34;&gt;https://lisp-journey.gitlab.io/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can connect to the running app with a Swank server to check and set
parameters, which is super helpful and harmless.&lt;/p&gt;

&lt;p&gt;It is possible to reload the whole app from within itself and I did it
with no hiccups for a couple years, but it isn&amp;rsquo;t necessary the most
reliable, easiest to set up and fastest method. You can do it, but
nobody forces you to do this because you are running CL in
production. You can use the industry&amp;rsquo;s boring and best practices
too. &lt;strong&gt;Common Lisp doesn&amp;rsquo;t inforce a &amp;ldquo;big ball of mud&amp;rdquo;
approach&lt;/strong&gt;. Develop locally, use Git, use a CI, deploy a binary…&lt;/p&gt;

&lt;p&gt;Every thing that I learned I documented it along the way in the Cookbook ;)&lt;/p&gt;

&lt;p&gt;Another app that I&amp;rsquo;ll mention but about which &lt;a href=&#34;http://lisp-journey.gitlab.io/blog/a-free-software-for-bookshops-to-show-their-catalogue-online/&#34;&gt;I also wrote earlier&lt;/a&gt; is my first web app. This one is open-source. It still runs :)&lt;/p&gt;



&lt;img src=&#34;/images/abstock-blason-extract.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt; &lt;/p&gt;



&lt;img src=&#34;https://gitlab.com/vindarel/abstock/-/raw/master/other-data.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;In this project I had my friend and colleague contribute five lines of
Lisp code to add a theme switcher in the backend that would help him
do the frontend. He had never written a line of Lisp before. Of
course, he did so by looking at my existing code to learn the existing
functions at hand, and he could do it because the project was easy to
install and run.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun get-template(template &amp;amp;optional (theme *theme*))
  &amp;quot;Loads template from the base templates directory or from the given theme templates directory if it exists.&amp;quot;
  (if (and (str:non-blank-string-p theme)
           (probe-file (asdf:system-relative-pathname &amp;quot;abstock&amp;quot; (str:concat &amp;quot;src/templates/themes/&amp;quot; theme &amp;quot;/&amp;quot; template))))
      ;; then
      (str:concat &amp;quot;themes/&amp;quot; theme &amp;quot;/&amp;quot; template)
      ;; else :D
      template))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;He had to annotate the &lt;code&gt;if&lt;/code&gt; branches :] This passed the code review.&lt;/p&gt;

&lt;h1 id=&#34;lasting-words&#34;&gt;Lasting words&lt;/h1&gt;

&lt;p&gt;The 5th script/app is already on the way, and the next ones are
awaiting that I open their .docx specification files. This one was a
bit harder but the Lisp side was done sucessfully with the efficient
collaboration of another freelance lisper (&lt;a href=&#34;http://kevinize.com&#34;&gt;Kevin&lt;/a&gt; to not name him).&lt;/p&gt;

&lt;p&gt;All those tasks (read a DB, transform data…) are very mundane.&lt;/p&gt;

&lt;p&gt;They are everywhere. They don&amp;rsquo;t always need supercharged web framework or integrations.&lt;/p&gt;

&lt;p&gt;You have plenty of opportunities to make yourself a favor, and use Common Lisp in the wild. Not counting the super-advanced domains where Lisp excels at ;)&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&#34;links&#34;&gt;Links&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;https://lispcookbook.github.io/cl-cookbook/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;awesome-cl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;companies using Common Lisp in production (at least the ones we know)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=WEALLLOVELISPCLOS2&#34;&gt;Common Lisp course in videos&lt;/a&gt; &amp;ndash; it helps me, and you ;) I added &lt;em&gt;9 videos about CLOS&lt;/em&gt; last month, and more are coming. It&amp;rsquo;s 86 minutes of an efficient code-first approach, out of 7+ hours of total content in the course. After this chapter you know enough to read the sources of the Hunchentoot web server or of the Kandria game.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I have done some preliminary Common Lisp exploration prior to this course but had a lot of questions regarding practical use and development workflows. This course was amazing for this! I learned a lot of useful techniques for actually writing the code in Emacs, as well as conversational explanations of concepts that had previously confused me in text-heavy resources. Please keep up the good work and continue with this line of topics, it is well worth the price! [Preston, October of 2024]&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Common Lisp: equality functions explained (=, eq, equal, string= et all)</title>
      <link>/blog/common-lisp-equality-predicates/</link>
      <pubDate>Fri, 23 Aug 2024 12:53:29 +0200</pubDate>
      
      <guid>/blog/common-lisp-equality-predicates/</guid>
      <description>

&lt;p&gt;Common Lisp has various equality functions: &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;eq&lt;/code&gt;, &lt;code&gt;eql&lt;/code&gt;, &lt;code&gt;equal&lt;/code&gt;,
&lt;code&gt;equalp&lt;/code&gt;, &lt;code&gt;string-equal&lt;/code&gt;, &lt;code&gt;char-equal&lt;/code&gt;… but what are the differences??
We tell you everything, with examples.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As usual, this is &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/equality.html&#34;&gt;best read on the Common Lisp Cookbook&lt;/a&gt; (a new page added on August, 2024). This is where it will get the updates&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt; is only for numbers and &lt;code&gt;equal&lt;/code&gt; is the equality predicate that works on many things.&lt;/li&gt;
&lt;li&gt;you can&amp;rsquo;t overload built-in operators such as &lt;code&gt;=&lt;/code&gt; or &lt;code&gt;equal&lt;/code&gt; for your own classes, unless you use a library.&lt;/li&gt;
&lt;li&gt;when you manipulate strings with functional built-ins (&lt;code&gt;remove-if&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;…) and you are surprised to get no results, you probably forgot the &lt;code&gt;:test&lt;/code&gt; key argument: &lt;code&gt;(find &amp;quot;foo&amp;quot; &#39;(&amp;quot;hello&amp;quot; &amp;quot;foo&amp;quot;) :test #&#39;equal)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#-is-for-numbers-beware-of-nil&#34;&gt;&lt;code&gt;=&lt;/code&gt; is for numbers (beware of &lt;code&gt;NIL&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#eq-is-low-level-think-pointers-position-in-memory&#34;&gt;&lt;code&gt;eq&lt;/code&gt; is low-level. Think pointers, position in memory.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#eql-is-a-better-eq-also-for-numbers-of-same-types-and-characters&#34;&gt;&lt;code&gt;eql&lt;/code&gt; is a better &lt;code&gt;eq&lt;/code&gt; also for numbers of same types and characters.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#equal-is-also-for-strings-for-objects-whose-printed-representation-is-similar&#34;&gt;&lt;code&gt;equal&lt;/code&gt; is also for strings (for objects whose printed representation is similar).&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#equalp-is-case-insensitive-for-strings-and-for-numerical-value-of-numbers&#34;&gt;&lt;code&gt;equalp&lt;/code&gt; is case-insensitive for strings and for numerical value of numbers.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-comparison-functions&#34;&gt;Other comparison functions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#null&#34;&gt;&lt;code&gt;null&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#eql-is-used-by-default-by-many-cl-built-ins&#34;&gt;&lt;code&gt;eql&lt;/code&gt; is used by default by many CL built-ins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#char-equal&#34;&gt;&lt;code&gt;char-equal&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#strings-and-string-equal&#34;&gt;strings and &lt;code&gt;string-equal&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#compare-trees-with-tree-equal&#34;&gt;Compare trees with &lt;code&gt;tree-equal&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#compare-function-table-to-compare-against-this-use-that-function&#34;&gt;Compare function table: to compare against (this), use (that) function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#how-to-compare-your-own-objects-aka-built-in-functions-are-not-object-oriented&#34;&gt;How to compare your own objects AKA built-in functions are not object-oriented&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#credits&#34;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#see-also&#34;&gt;See also&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;is-for-numbers-beware-of-nil&#34;&gt;&lt;code&gt;=&lt;/code&gt; is for numbers (beware of &lt;code&gt;NIL&lt;/code&gt;)&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;=&lt;/code&gt; function compares the value of two or more numbers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(= 2 2) ;; =&amp;gt; T
(= 2 2.0 2 2) ;; =&amp;gt; T
(= 2 4/2) ;; =&amp;gt; T

(= 2 42) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but &lt;code&gt;=&lt;/code&gt; is only for numbers. In the below example we get an error with
the interactive debugger. We show the error message, the condition
type, and the backtrace, from SBCL.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(= 2 NIL)
;; =&amp;gt; ERROR:
The value
  NIL
is not of type
  NUMBER
when binding SB-KERNEL::Y

   [Condition of type TYPE-ERROR]

Restarts:
  …

Backtrace:
  0: (SB-KERNEL:TWO-ARG-= 2 NIL) [external]
  1: (SB-VM::GENERIC-=)
  2: (= 2 NIL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note how &lt;code&gt;SB-KERNEL::Y&lt;/code&gt; refers to an internal variable of the
compiler. No, you don&amp;rsquo;t have a &lt;code&gt;Y&lt;/code&gt; in your code.&lt;/p&gt;

&lt;p&gt;As a consequence, if your equality check with numbers might contain
NILs, you can use &lt;code&gt;equalp&lt;/code&gt;, or encapsulate your variables with &lt;code&gt;(or …
0)&lt;/code&gt;, or do prior checks with &lt;code&gt;(null …)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;eq-is-low-level-think-pointers-position-in-memory&#34;&gt;&lt;code&gt;eq&lt;/code&gt; is low-level. Think pointers, position in memory.&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;(eq x y) is true if and only if x and y are the same identical object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;eq&lt;/code&gt; works for symbols and keywords.&lt;/p&gt;

&lt;p&gt;Those are true:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eq :a :a)
(eq &#39;a &#39;a)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we compare an object with itself, it is &lt;code&gt;eq&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((x &#39;(a . b)))
  (eq x x))
;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;eq&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; work to compare numbers, lists, strings and other
compound objects. It looks like it can, but it isn&amp;rsquo;t specified to be
true for all implementations.&lt;/p&gt;

&lt;p&gt;As such, &lt;code&gt;eq&lt;/code&gt; works for numbers on my implementation, but it might not on yours:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eq 2 2) ;; =&amp;gt; T or NIL, this is not specified
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An implementation might allocate the exact same position in memory for
the same number, but it might not. This isn&amp;rsquo;t dictated by the
standard.&lt;/p&gt;

&lt;p&gt;Likewise, these might depend on the implementation:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eq &#39;(a . b) &#39;(a . b)) ;; might be true or false.
(eq #\a #\a) ;; true or false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Comparing lists or strings are false:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eq (list &#39;a) (list &#39;a)) ;; =&amp;gt; NIL
(eq &amp;quot;a&amp;quot; &amp;quot;a&amp;quot;) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;those strings (vectors of characters) are not equal by &lt;code&gt;eq&lt;/code&gt; because the compiler might have
created two different string objects in memory.&lt;/p&gt;

&lt;h2 id=&#34;eql-is-a-better-eq-also-for-numbers-of-same-types-and-characters&#34;&gt;&lt;code&gt;eql&lt;/code&gt; is a better &lt;code&gt;eq&lt;/code&gt; also for numbers of same types and characters.&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;eql&lt;/code&gt; predicate is true if its arguments are &lt;code&gt;eq&lt;/code&gt;, or if they are numbers of the same type with the same value, or if they are character objects that represent the same character.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In terms of usefulness, we could say that &lt;code&gt;eq&lt;/code&gt; &amp;lt; &lt;code&gt;eql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now this number comparison is true:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eql 3 3) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but beware, this one isn&amp;rsquo;t because 3 and 3.0 are not of the same type
(integer and single float):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eql 3 3.0) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;for complex numbers:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eql #c(3 -4) #c(3 -4)) ;; is true.
(eql #c(3 -4.0) #c(3 -4)) ;; is false (because of -4.0 and -4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Comparing two characters works:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eql #\A #\A) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we still can&amp;rsquo;t compare lists or cons cells:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eql (cons &#39;a &#39;b) (cons &#39;a &#39;b)) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;equal-is-also-for-strings-for-objects-whose-printed-representation-is-similar&#34;&gt;&lt;code&gt;equal&lt;/code&gt; is also for strings (for objects whose printed representation is similar).&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;equal&lt;/code&gt; predicate is true if its arguments are structurally similar (isomorphic) objects. A rough rule of thumb is that two objects are &lt;code&gt;equal&lt;/code&gt; if and only if their printed representations are the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, conceptually, we could say that &lt;code&gt;eq&lt;/code&gt; &amp;lt; &lt;code&gt;eql&lt;/code&gt; &amp;lt; &lt;code&gt;equal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can still not compare numbers of different types:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equal 3 3.0) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but we can now compare lists and cons cells. Indeed, their printed
representation is the same. No matter this time if they are different
objects in memory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equal (cons &#39;a &#39;b) (cons &#39;a &#39;b)) ;; =&amp;gt; T

(equal (list &#39;a) (list &#39;a)) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can compare strings!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equal &amp;quot;Foo&amp;quot; &amp;quot;Foo&amp;quot;) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;No matter if they are different objects in memory:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equal &amp;quot;Foo&amp;quot; (copy-seq &amp;quot;Foo&amp;quot;)) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Case is important. Indeed, &amp;ldquo;FOO&amp;rdquo; doesn&amp;rsquo;t print the same as &amp;ldquo;foo&amp;rdquo;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equal &amp;quot;FOO&amp;quot; &amp;quot;foo&amp;quot;) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;equalp-is-case-insensitive-for-strings-and-for-numerical-value-of-numbers&#34;&gt;&lt;code&gt;equalp&lt;/code&gt; is case-insensitive for strings and for numerical value of numbers.&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Two objects are &lt;code&gt;equalp&lt;/code&gt; if they are &lt;code&gt;equal&lt;/code&gt;; if they are characters and satisfy &lt;code&gt;char-equal&lt;/code&gt;, which ignores alphabetic case and certain other attributes of characters; if they are numbers and have the same numerical value, even if they are of different types; or if they have components that are all &lt;code&gt;equalp&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Continuing with our ordering, we could say that &lt;code&gt;eq&lt;/code&gt; &amp;lt; &lt;code&gt;eql&lt;/code&gt; &amp;lt; &lt;code&gt;equal&lt;/code&gt; &amp;lt; &lt;code&gt;equalp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can compare two numbers, looking at their value, even if they have different types:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equalp 3 3.0) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now look at our string comparison:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(equalp &amp;quot;FOO&amp;quot; &amp;quot;foo&amp;quot;) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;equalp&lt;/code&gt; is case *in*sensitive for strings because a string is a
sequence of characters, &lt;code&gt;equalp&lt;/code&gt; compares all of its components and it
uses &lt;code&gt;char-equal&lt;/code&gt; for characters, which ignores the characters&amp;rsquo; case.&lt;/p&gt;

&lt;h2 id=&#34;other-comparison-functions&#34;&gt;Other comparison functions&lt;/h2&gt;

&lt;h3 id=&#34;null&#34;&gt;&lt;code&gt;null&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The function &lt;code&gt;null&lt;/code&gt; returns true if its one argument is NIL.&lt;/p&gt;

&lt;h3 id=&#34;eql-is-used-by-default-by-many-cl-built-ins&#34;&gt;&lt;code&gt;eql&lt;/code&gt; is used by default by many CL built-ins&lt;/h3&gt;

&lt;p&gt;This is a common issue for newcomers who manipulate
strings. Sometimes, you use a CL built-in function and you are puzzled
why you get no result.&lt;/p&gt;

&lt;p&gt;Look at this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find &amp;quot;foo&amp;quot; (list &amp;quot;test&amp;quot; &amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;))
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we want to know if the string &amp;ldquo;foo&amp;rdquo; exists in the given list. We get
NIL. What&amp;rsquo;s happening?&lt;/p&gt;

&lt;p&gt;This CL built-in function, as all that work for sequences, use &lt;code&gt;eql&lt;/code&gt;
for testing each elements. But &lt;code&gt;(eql &amp;quot;foo&amp;quot; &amp;quot;foo&amp;quot;)&lt;/code&gt; won&amp;rsquo;t work for
strings. We need to use another test function.&lt;/p&gt;

&lt;p&gt;All of those functions accept a &lt;code&gt;:test&lt;/code&gt; keyword parameter, that allows
you to change the test function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find &amp;quot;foo&amp;quot; (list &amp;quot;test&amp;quot; &amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;) :test #&#39;equal)
;; =&amp;gt; &amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also use &lt;code&gt;equalp&lt;/code&gt; to ignore the string case:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find &amp;quot;FOO&amp;quot; (list &amp;quot;test&amp;quot; &amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;) :test #&#39;equalp)
;; =&amp;gt; &amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will find more examples about those built-in functions in &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/data-structures.html&#34;&gt;data-structures&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;char-equal&#34;&gt;&lt;code&gt;char-equal&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;We have a special operator to compare characters:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;char-equal&lt;/code&gt; ignores alphabetic case and certain other attributes of characters&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;strings-and-string-equal&#34;&gt;strings and &lt;code&gt;string-equal&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;string-equal&lt;/code&gt; has a specific function signature to compare strings
and substrings (you can specify the &lt;em&gt;start&lt;/em&gt; and &lt;em&gt;end&lt;/em&gt; boundaries for
the comparison), but be aware that it uses &lt;code&gt;char-equal&lt;/code&gt;, so the
comparison is case-*in*sensitive. And it works with symbols.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(string-equal :foo &amp;quot;foo&amp;quot;) ;; =&amp;gt; T
(string-equal :foo &amp;quot;FOO&amp;quot;) ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is its docstring:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;STRING-EQUAL

This is a function in package COMMON-LISP

Signature
(string1 string2 &amp;amp;key (start1 0) end1 (start2 0) end2)

Given two strings (string1 and string2), and optional integers start1,
start2, end1 and end2, compares characters in string1 to characters in
string2 (using char-equal).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See also our page &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/strings.html&#34;&gt;strings.html&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;compare-trees-with-tree-equal&#34;&gt;Compare trees with &lt;code&gt;tree-equal&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Here you have it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;tree-equal&lt;/code&gt; returns T if X and Y are isomorphic trees with identical leaves&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;compare-function-table-to-compare-against-this-use-that-function&#34;&gt;Compare function table: to compare against (this), use (that) function&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-txt&#34;&gt;To compare against...      Use...

Objects/Structs            EQ

NIL                        EQ (but the function NULL is more concise and probably cheaper)

T                          EQ (or just the value but then you don&#39;t care for the type)

Precise numbers            EQL

Floats                     =

Characters                 EQL or CHAR-EQUAL

Lists, Conses, Sequences   EQ (if you want the exact same object)
                           EQUAL (if you just care about elements)

Strings                    EQUAL (case-sensitive), EQUALP (case-insensitive)
                           STRING-EQUAL (if you throw symbols into the mix)

Trees (lists of lists)     TREE-EQUAL (with appropriate :TEST argument)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;how-to-compare-your-own-objects-aka-built-in-functions-are-not-object-oriented&#34;&gt;How to compare your own objects AKA built-in functions are not object-oriented&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;eq&lt;/code&gt; to check that two objects are identical, that they are the same object in memory&lt;/p&gt;

&lt;p&gt;If you want to compare your own objects with a logic of your own (for
example, two &amp;ldquo;person&amp;rdquo; objects will be considered equal if they have
the same name and surname), you can&amp;rsquo;t specialize a built-in function
for this. Use your own &lt;code&gt;person=&lt;/code&gt; or similar function, or use a library (see our links below).&lt;/p&gt;

&lt;p&gt;While this can be seen as a limitation, not using generic functions
has the advantage of being (much) faster.&lt;/p&gt;

&lt;p&gt;As an example, let&amp;rsquo;s consider the &lt;code&gt;person&lt;/code&gt; class from the CLOS tutorial:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name
    :initarg :name
    :accessor name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s create two person objects, they have the same name but are two different objects:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *p1* (make-instance &#39;person :name &amp;quot;me&amp;quot;))
(defparameter *p2-same-name* (make-instance &#39;person :name &amp;quot;me&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Use &lt;code&gt;eq&lt;/code&gt; to compare two objects:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(eq *p1* *p1*) ;; =&amp;gt; T
(eq *p1* *p2-same-name*) ;; =&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use our own &lt;code&gt;person=&lt;/code&gt; method to compare different objects and decide when they are equal:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod person= (p1 p2)
  (string= (name p1) (name p2)))

(person= *p1* *p2-same-name*)  ;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you really want to use &lt;code&gt;=&lt;/code&gt; or &lt;code&gt;equal&lt;/code&gt;, use a library, see below.&lt;/p&gt;

&lt;h1 id=&#34;credits&#34;&gt;Credits&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node74.html&#34;&gt;CLtL2: Equality Predicates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the compare table: &lt;a href=&#34;https://stackoverflow.com/questions/547436/whats-the-difference-between-eq-eql-equal-and-equalp-in-common-lisp&#34;&gt;Leslie P. Polzer on Stack-Overflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;see-also&#34;&gt;See also&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/karlosz/equals/&#34;&gt;equals&lt;/a&gt; - generic equality for Common Lisp.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/alex-gutev/generic-cl/&#34;&gt;generic-cl&lt;/a&gt; - a generic function interface to CL built-ins.

&lt;ul&gt;
&lt;li&gt;we can use &lt;code&gt;=&lt;/code&gt; or &lt;code&gt;&amp;lt;&lt;/code&gt; on our own custom objects.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Oh no, I started a Magit-like plugin for the Lem editor</title>
      <link>/blog/oh-no-i-started-a-magit-like-plugin-for-the-lem-editor/</link>
      <pubDate>Thu, 14 Mar 2024 13:11:34 +0100</pubDate>
      
      <guid>/blog/oh-no-i-started-a-magit-like-plugin-for-the-lem-editor/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://lem-project.github.io&#34;&gt;Lem&lt;/a&gt; is an awesome project. It&amp;rsquo;s an
editor buit in Common Lisp, ready to use out of the box for Common
Lisp, that supports more languages and modes (Python, Rust, Elixir,
Go, JavaScript, TypeScript, Haskell, Java, Nim, Dart, OCaml, Scala,
Swift, shell, asm, but also markdown, ascii, JSON, HTML and CSS, SQL…)
thanks to, in part, its built-in LSP support.&lt;/p&gt;

&lt;p&gt;I took the challenge to add an interactive interface for Git, à la
Magit, because you know, despite all its features (good vim mode,
project-aware commands, grep, file tree view and directory mode,
multiple cursors, tabs…), there&amp;rsquo;s so much an editor should do to be
useful all day long.&lt;/p&gt;

&lt;p&gt;Now, for a &lt;strong&gt;Git&lt;/strong&gt; project (and to a lower extent, &lt;strong&gt;Fossil&lt;/strong&gt; and
&lt;strong&gt;Mercurial&lt;/strong&gt; ones) we can &lt;strong&gt;see its status, stage changes, commit, push &amp;amp;
pull, start an interactive rebase&lt;/strong&gt;…&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/lem-status.png&#34; style=&#34;max-width: 100%&#34;/&gt;&lt;/p&gt;

&lt;p&gt;I like the shape it is taking, and frankly, what I have been able to
assemble in a continuously successful hack session is a tribute to
what @cxxxr and the early contributors built. &lt;strong&gt;Lem&amp;rsquo;s codebase is easily
explorable&lt;/strong&gt; (more so in Lem itself of course, think Emacs in steroïds
with greater Common Lisp power), clear, and fun. Come to the Discord
or watch the repository and see how new contributors easily add new
features.&lt;/p&gt;

&lt;p&gt;I didn&amp;rsquo;t even have to build an UI interface, fortunately. I started
with the built-in interactive grep mode, and built from there.&lt;/p&gt;

&lt;p&gt;Enough talk, what can we do with Lem/legit as of today? After that, we&amp;rsquo;ll discuss some implementation details.&lt;/p&gt;

&lt;p&gt;Disclaimer: there&amp;rsquo;s room for collaboration ;)&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#lemlegit---manual&#34;&gt;Lem/legit - manual&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#status&#34;&gt;Status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#load&#34;&gt;Load&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#help&#34;&gt;Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#m-x-legit-status&#34;&gt;M-x legit-status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#navigation&#34;&gt;Navigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#stage-or-unstage-files-diff-hunks-s-u&#34;&gt;Stage or unstage files, diff hunks (s, u)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#discard-changes-to-a-file&#34;&gt;Discard changes to a file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#commit&#34;&gt;Commit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#branches-push-pull&#34;&gt;Branches, push, pull&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#interactive-rebase&#34;&gt;Interactive rebase&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#abort-continue-skip&#34;&gt;Abort, continue, skip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fossil&#34;&gt;Fossil&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mercurial&#34;&gt;Mercurial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#customization&#34;&gt;Customization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#implementation-details&#34;&gt;Implementation details&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#calls&#34;&gt;Calls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#interactive-rebase-1&#34;&gt;Interactive rebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#displaying-data-actionable-links&#34;&gt;Displaying data, actionable links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#todos&#34;&gt;TODOs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-words&#34;&gt;Closing words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;lem-legit-manual&#34;&gt;Lem/legit - manual&lt;/h1&gt;

&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px;&#34;&gt;
&lt;!-- if inside a &lt;p&gt; then bootstrap adds 10px padding to the bottom --&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; you&#39;d better read the latest manual on Lem&#39;s repository: &lt;a href=&#34;https://github.com/lem-project/lem/blob/main/extensions/legit/README.md&#34;&gt;https://github.com/lem-project/lem/blob/main/extensions/legit/README.md&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;legit&lt;/code&gt;&amp;rsquo;s main focus is to support Git operations, but it also has
preliminary support for other VCSs (Fossil, Mercurial).&lt;/p&gt;

&lt;p&gt;We can currently open a &lt;strong&gt;status&lt;/strong&gt; window, &lt;strong&gt;stage&lt;/strong&gt; and unstage files or diff hunks, &lt;strong&gt;commit&lt;/strong&gt; our changes or again start an &lt;strong&gt;interactive rebase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its main source of inspiration is, obviously, Magit.&lt;/p&gt;

&lt;h2 id=&#34;status&#34;&gt;Status&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;legit&lt;/code&gt; is in development. It isn&amp;rsquo;t finished nor complete nor at
feature parity with Magit nor suitable for mission-critical work. Use
at your own risk.&lt;/p&gt;

&lt;p&gt;However it should run a few operations smoothly.&lt;/p&gt;

&lt;h2 id=&#34;load&#34;&gt;Load&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;legit&lt;/code&gt; is built into Lem but it isn&amp;rsquo;t loaded by default. To load it, open a Lisp REPL (&lt;code&gt;M-x start-lisp-repl&lt;/code&gt;) or evaluate Lisp code (&lt;code&gt;M-:&lt;/code&gt;) and type:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload &amp;quot;lem/legit&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can start it with &lt;code&gt;C-x g&lt;/code&gt; or &lt;code&gt;M-x legit-status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/lem-status.png&#34; style=&#34;max-width: 100%&#34;/&gt;&lt;/p&gt;

&lt;h2 id=&#34;help&#34;&gt;Help&lt;/h2&gt;

&lt;p&gt;Press &lt;code&gt;?&lt;/code&gt; or &lt;code&gt;C-x ?&lt;/code&gt; to call &lt;code&gt;legit-help&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;m-x-legit-status&#34;&gt;M-x legit-status&lt;/h2&gt;

&lt;p&gt;The status windows show us, on the left:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the current branch&lt;/li&gt;
&lt;li&gt;the untracked files.&lt;/li&gt;
&lt;li&gt;the unstaged changes, staged changes,&lt;/li&gt;
&lt;li&gt;the latest commits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also warns us if a rebase is in process.&lt;/p&gt;

&lt;p&gt;and the window on the right shows us the file diffs or the commits&amp;rsquo; content.&lt;/p&gt;

&lt;p&gt;Refresh the status content with &lt;code&gt;g&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;navigation&#34;&gt;Navigation&lt;/h2&gt;

&lt;p&gt;We can navigate inside legit windows with &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;M-n&lt;/code&gt; and &lt;code&gt;M-p&lt;/code&gt; (go to next/previous section).&lt;/p&gt;

&lt;p&gt;To change windows, use the usual &lt;code&gt;M-o&lt;/code&gt; key from Lem.&lt;/p&gt;

&lt;p&gt;Quit with &lt;code&gt;q&lt;/code&gt; or &lt;code&gt;C-x 0&lt;/code&gt; (zero).&lt;/p&gt;

&lt;h2 id=&#34;stage-or-unstage-files-diff-hunks-s-u&#34;&gt;Stage or unstage files, diff hunks (s, u)&lt;/h2&gt;

&lt;p&gt;Stage changes with &amp;ldquo;s&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;When your cursor is on an &lt;code&gt;Unstaged change&lt;/code&gt; file, you can see the file
changes on the right, and you can stage the whole file with &lt;code&gt;s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also go to the diff window on the right, navigate the diff hunks with &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; and stage a hunk with &lt;code&gt;s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unstage a change with &lt;code&gt;u&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;discard-changes-to-a-file&#34;&gt;Discard changes to a file&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;k&lt;/code&gt;. Be careful, you can loose your changes.&lt;/p&gt;

&lt;h2 id=&#34;commit&#34;&gt;Commit&lt;/h2&gt;

&lt;p&gt;Pressing &lt;code&gt;c&lt;/code&gt; opens a new buffer where you can write your commit message.&lt;/p&gt;

&lt;p&gt;Validate with &lt;code&gt;C-c C-c&lt;/code&gt; and quit with &lt;code&gt;M-q&lt;/code&gt; (or &lt;code&gt;C-c C-k&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&#34;branches-push-pull&#34;&gt;Branches, push, pull&lt;/h2&gt;

&lt;p&gt;Checkout a branch with &lt;code&gt;b b&lt;/code&gt; (&amp;ldquo;b&amp;rdquo; followed by another &amp;ldquo;b&amp;rdquo;).&lt;/p&gt;

&lt;p&gt;Create a new branch with &lt;code&gt;b c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can push to the current remote branch with &lt;code&gt;P p&lt;/code&gt; and pull changes (fetch) with &lt;code&gt;F p&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px;&#34;&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; after pressing &#34;P&#34; or &#34;F&#34;, you will not see an intermediate window giving you choices. Just press &#34;P p&#34; one after the other.
&lt;/div&gt;

&lt;h2 id=&#34;interactive-rebase&#34;&gt;Interactive rebase&lt;/h2&gt;

&lt;p&gt;You can start a Git interactive rebase. Place the cursor on a commit you want to rebase from, and press &lt;code&gt;r i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will be dropped into the classical Git rebase file, that presents you commits and an action to apply on them: &lt;code&gt;pick&lt;/code&gt; the commit, &lt;code&gt;drop&lt;/code&gt; it, &lt;code&gt;fixup&lt;/code&gt;, edit, reword, squash…&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pick 26b3990f the following commit
pick 499ba39d some commit

# Commands:
# p, pick &amp;lt;commit&amp;gt; = use commit
# r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
# e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
# s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
# f, fixup &amp;lt;commit&amp;gt; = like &amp;quot;squash&amp;quot;, but discard this commit&#39;s log message
# x, exec &amp;lt;command&amp;gt; = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with &#39;git rebase --continue&#39;)
# d, drop &amp;lt;commit&amp;gt; = remove commit
# l, label &amp;lt;label&amp;gt; = label current HEAD with a name
# t, reset &amp;lt;label&amp;gt; = reset HEAD to a label
# m, merge [-C &amp;lt;commit&amp;gt; | -c &amp;lt;commit&amp;gt;] &amp;lt;label&amp;gt; [# &amp;lt;oneline&amp;gt;]
# .       create a merge commit using the original merge commit&#39;s
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c &amp;lt;commit&amp;gt; to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;legit&lt;/code&gt; binds keys to the rebase actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;p&lt;/code&gt; to &amp;ldquo;pick&amp;rdquo; the commit (the default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; to fixup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and so on.&lt;/p&gt;

&lt;p&gt;Validate anytime with &lt;code&gt;C-c C-c&lt;/code&gt; and abort with &lt;code&gt;C-c C-k&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px;&#34;&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; at the time of writing, &#34;reword&#34; and &#34;edit&#34; are not supported.
&lt;/div&gt;

&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px;&#34;&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; the interactive rebase is currently Unix only. This is due to the short shell script we use to control the Git process. Come join us if you know how to &#34;trap some-fn SIGTERM&#34; for Windows plateforms.
&lt;/div&gt;

&lt;h3 id=&#34;abort-continue-skip&#34;&gt;Abort, continue, skip&lt;/h3&gt;

&lt;p&gt;In any &lt;code&gt;legit&lt;/code&gt; window, type &lt;code&gt;r a&lt;/code&gt; to abort a rebase process (if it was
started by you inside Lem or by another process), &lt;code&gt;r c&lt;/code&gt; to call &lt;code&gt;git rebase --continue&lt;/code&gt; and &lt;code&gt;r s&lt;/code&gt; to call &lt;code&gt;git rebase --skip&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;fossil&#34;&gt;Fossil&lt;/h2&gt;

&lt;p&gt;We have basic Fossil support: see current branch, add change, commit.&lt;/p&gt;

&lt;h2 id=&#34;mercurial&#34;&gt;Mercurial&lt;/h2&gt;

&lt;p&gt;We have basic Mercurial support.&lt;/p&gt;

&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;lem/porcelain&lt;/code&gt; package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*git-base-arglist*&lt;/code&gt;: the Git program, to be appended command-line options. Defaults to &lt;code&gt;(list &amp;quot;git&amp;quot;)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;=&amp;gt; you can change the default call to the git binary.&lt;/p&gt;

&lt;p&gt;Same with &lt;code&gt;*fossil-base-args*&lt;/code&gt; and &lt;code&gt;*hg-base-arglist*&lt;/code&gt; (oops, a name mismatch).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*nb-latest-commits*&lt;/code&gt;: defaults to 10&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*branch-sort-by*&lt;/code&gt;: when listing branches, sort by this field name. Prefix with &amp;ldquo;-&amp;rdquo; to sort in descending order. Defaults to &amp;ldquo;-creatordate&amp;rdquo;, to list the latest used branches first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*file-diff-args*&lt;/code&gt;: defaults to &lt;code&gt;(list &amp;quot;diff&amp;quot; &amp;quot;--no-color&amp;quot;)&lt;/code&gt;. Arguments to display the file diffs. Will be surrounded by the git binary and the file path. For staged files, &amp;ndash;cached is added by the command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a project is managed by more than one VCS, &lt;code&gt;legit&lt;/code&gt; takes the first VCS defined in &lt;code&gt;*vcs-existence-order*&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *vcs-existence-order*
  &#39;(
    git-project-p
    fossil-project-p
    hg-project-p
    ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where these symbols are functions with no arguments that return two values: a truthy value if the current project is considered a Git/Fossil/Mercurial project, and a keyword representing the VCS: &lt;code&gt;:git&lt;/code&gt;, &lt;code&gt;:fossil&lt;/code&gt;, &lt;code&gt;:hg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hg-project-p ()
  &amp;quot;Return t if we find a .hg/ directory in the current directory (which should be the project root. Use `lem/legit::with-current-project`).&amp;quot;
  (values (uiop:directory-exists-p &amp;quot;.hg&amp;quot;)
          :hg))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Variables and parameters in the &lt;code&gt;lem/legit&lt;/code&gt; package. They might not be exported.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*legit-verbose*&lt;/code&gt;: If non nil, print some logs on standard output (terminal) and create the hunk patch file on disk at (lem-home)/lem-hunk-latest.patch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;=&amp;gt; to help debugging&lt;/p&gt;

&lt;p&gt;see sources in &lt;code&gt;/extensions/legit/&lt;/code&gt;&lt;/p&gt;

&lt;h1 id=&#34;implementation-details&#34;&gt;Implementation details&lt;/h1&gt;

&lt;h2 id=&#34;calls&#34;&gt;Calls&lt;/h2&gt;

&lt;p&gt;Repository data is retrieved with calls to the VCS binary. We have a POC to read some data directly from the Git objects (proactively looking for best efficiency) using &lt;a href=&#34;https://github.com/fiddlerwoaroof/cl-git&#34;&gt;cl-git&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Basically, we get Git status data with &lt;code&gt;git status --porcelain=v1&lt;/code&gt;. This outputs something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; A project/settings.lisp
 M project/api.lisp
?? project/search/datasources
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we output this a to a string and we parse it.&lt;/p&gt;

&lt;h2 id=&#34;interactive-rebase-1&#34;&gt;Interactive rebase&lt;/h2&gt;

&lt;p&gt;The interactive rebase currently uses a Unix-only shell script.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;git rebase --interactive&lt;/code&gt;, the Git program creates a
special file in &lt;code&gt;.git/rebase-merge/git-rebase-merge-todo&lt;/code&gt;, opens it
with your $EDITOR in the terminal, lets you edit it (change a &amp;ldquo;pick&amp;rdquo;
to &amp;ldquo;fixup&amp;rdquo;, &amp;ldquo;reword&amp;rdquo; etc), and on exit it interprets the file and runs
the required Git operations. What we want is to &lt;em&gt;not&lt;/em&gt; use Git&amp;rsquo;s
default program, edit the file with Lem and our special Legit mode
that binds keys for quick actions (press &amp;ldquo;f&amp;rdquo; for &amp;ldquo;fixup&amp;rdquo; etc). So we
bind the shell&amp;rsquo;s $EDITOR to a dummy editor, this shell script:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;function ok {
    exit 0
}

trap ok SIGTERM
echo &amp;quot;dumbrebaseeditor_pid:$$&amp;quot;

while :
do
        sleep 0.1
done
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This script doesn&amp;rsquo;t simulate an editor, it waits, so we can edit the
rebase file with Lem, but this script catches a SIGTERM signal and
exits successfully, so git-rebase is happy and terminates the rebase
and all is well.&lt;/p&gt;

&lt;p&gt;But that&amp;rsquo;s Unix only.&lt;/p&gt;

&lt;p&gt;On that matter Magit seems to be doing black magic.&lt;/p&gt;

&lt;h2 id=&#34;displaying-data-actionable-links&#34;&gt;Displaying data, actionable links&lt;/h2&gt;

&lt;p&gt;The basic function to write content to a buffer is&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(insert-string point s :read-only t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this is how you make actionable links:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(put-text-property start end :visit-file-function function))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where &lt;code&gt;:visit-file-function&lt;/code&gt; is any keyword you want, and &lt;code&gt;function&lt;/code&gt;
is any lambda function you want. So, how to make any link useful? Create a lambda, make it close over any variables you want, &amp;ldquo;store&amp;rdquo; it in a link, and later on read the attribute at point with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(text-property-at point :visit-file-function)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where &lt;code&gt;point&lt;/code&gt; can be &lt;code&gt;(buffer-point (window-buffer *my-window*))&lt;/code&gt; for instance.&lt;/p&gt;

&lt;p&gt;Now create a mode, add keybindings and you&amp;rsquo;re ready to go.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Legit diff mode: view diffs.
;; We use the existing patch-mode and supercharge it with our keys.
(define-major-mode legit-diff-mode lem-patch-mode:patch-mode
    (:name &amp;quot;legit-diff&amp;quot;
     :syntax-table lem-patch-mode::*patch-syntax-table*
     :keymap *legit-diff-mode-keymap*)
  (setf (variable-value &#39;enable-syntax-highlight) t))

;; git commands.
;; Some are defined on peek-legit too.
(define-key *global-keymap* &amp;quot;C-x g&amp;quot; &#39;legit-status)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or a minor mode:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-minor-mode peek-legit-mode
    (:name &amp;quot;Peek&amp;quot;
     :keymap *peek-legit-keymap*)
  (setf (not-switchable-buffer-p (current-buffer)) t))

;; Git commands
;; Some are defined on legit.lisp for this keymap too.
(define-key *peek-legit-keymap* &amp;quot;s&amp;quot; &#39;peek-legit-stage-file)
(define-key *peek-legit-keymap* &amp;quot;u&amp;quot; &#39;peek-legit-unstage-file)
(define-key *peek-legit-keymap* &amp;quot;k&amp;quot; &#39;peek-legit-discard-file)
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;todos&#34;&gt;TODOs&lt;/h1&gt;

&lt;p&gt;Much needs to be done, if only to have a better discoverable UX.&lt;/p&gt;

&lt;p&gt;First:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interactive rebase: support reword, edit.&lt;/li&gt;
&lt;li&gt;show renamed files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;visual submenu to pick subcommands&lt;/li&gt;
&lt;li&gt;view log&lt;/li&gt;
&lt;li&gt;stage only selected region (more precise than hunks)&lt;/li&gt;
&lt;li&gt;unstage/stage/discard multiple files&lt;/li&gt;
&lt;li&gt;many, many more commands, settings and switches&lt;/li&gt;
&lt;li&gt;mouse context menus&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;closing-words&#34;&gt;Closing words&lt;/h1&gt;

&lt;p&gt;You&amp;rsquo;ll be surprised by all Lem&amp;rsquo;s features and how easy it is to add features.&lt;/p&gt;

&lt;p&gt;I believe it doesn&amp;rsquo;t make much sense to &amp;ldquo;port Magit to Lem&amp;rdquo;. The UIs
are different, the text displaying mechanism is different, etc. It&amp;rsquo;s
faster to re-implement the required functionality, without the
cruft. And look, I started, it&amp;rsquo;s possible.&lt;/p&gt;

&lt;p&gt;But, sad me, I didn&amp;rsquo;t plan to be involved in yet another side project,
as cool and motivating as it might be :S&lt;/p&gt;

&lt;hr /&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lem-project.github.io/usage/usage/&#34;&gt;https://lem-project.github.io/usage/usage/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lem-project/lem/&#34;&gt;https://github.com/lem-project/lem/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://discord.gg/NHzqbw4zVR&#34;&gt;https://discord.gg/NHzqbw4zVR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://opencollective.com/lem&#34;&gt;https://opencollective.com/lem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;last but not least, &lt;a href=&#34;https://ko-fi.com/vindarel&#34;&gt;https://ko-fi.com/vindarel&lt;/a&gt; &amp;amp; &lt;a href=&#34;https://github.com/sponsors/vindarel/&#34;&gt;https://github.com/sponsors/vindarel/&lt;/a&gt; ;)&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Celebrating 1001 learners on my Common Lisp course 🥳</title>
      <link>/blog/celebrating-1001-learners-on-my-common-lisp-course/</link>
      <pubDate>Wed, 14 Feb 2024 17:05:44 +0100</pubDate>
      
      <guid>/blog/celebrating-1001-learners-on-my-common-lisp-course/</guid>
      <description>&lt;p&gt;I just got &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;1001 learners on my Common Lisp
course&lt;/a&gt;
on Udemy. Thanks everybody for your support, here or elsewhere!&lt;/p&gt;

&lt;p&gt;Starting with CL was honestly not easy. The first thing I did was
writing the &amp;ldquo;data structures&amp;rdquo; page on the Cookbook, bewildered that it
didn&amp;rsquo;t exist yet. A few years and a few projects later, this course
allows me to share more, learn more, have fun, and have some rewards
to keep the motivation up.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/udemy-course.png&#34; style=&#34;max-width: 1000px&#34; href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34; title=&#34;Learning Common Lisp in videos on my Udemy course.&#34;/&gt;&lt;/p&gt;

&lt;p&gt;I know the course isn&amp;rsquo;t complete by any means, I want to add many
chapters, both advanced topics but easier material for newcomers as
well (beware, my course isn&amp;rsquo;t for total beginners in a Lisp
language). The next one, and soon©, will be all about CLOS. In the
meantime, I don&amp;rsquo;t abandon you, I enhance the Cookbook, I publish some
videos on Youtube (&lt;a href=&#34;https://www.youtube.com/watch?v=h_noB1sI_e8&#34;&gt;last one: web development in Common Lisp, part 1
and part 2&lt;/a&gt;), I work on
starter kits or on newcomer-friendly libraries ;)&lt;/p&gt;

&lt;p&gt;Thanks again,&lt;/p&gt;

&lt;p&gt;don&amp;rsquo;t hesitate to share the link with a friend or a colleague ;)&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=CELEBRATE1001&#34;&gt;link with a coupon until March, 13th 2024&lt;/a&gt;. (student? Get in touch for a free link)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;more information on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe src=&#34;https://emacs.ch/@louis/111937239776148099/embed&#34; width=&#34;400&#34; allowfullscreen=&#34;allowfullscreen&#34; sandbox=&#34;allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-forms&#34;&gt;&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>Latest string manipulation functions in the STR library</title>
      <link>/blog/latest-string-manipulation-functions/</link>
      <pubDate>Fri, 22 Dec 2023 16:52:51 +0100</pubDate>
      
      <guid>/blog/latest-string-manipulation-functions/</guid>
      <description>

&lt;p&gt;We just released &lt;a href=&#34;https://github.com/vindarel/cl-str/releases/tag/0.21&#34;&gt;cl-str
v0.21&lt;/a&gt;. It&amp;rsquo;s
been a while since the last release, and many enhancements make it
more useful than ever. Let&amp;rsquo;s review the changes, the newest first.&lt;/p&gt;

&lt;p&gt;But first, I want to you thank everyone who contributed, by sending
pull requests or feedback. Special thanks to
&lt;a href=&#34;https://github.com/kilianmh&#34;&gt;@kilianmh&lt;/a&gt; who suddenly appeared one
day, helped with new features as well as grunt work, and who is now a
co-maintainer.&lt;/p&gt;

&lt;h2 id=&#34;split-by-regex&#34;&gt;&lt;code&gt;split&lt;/code&gt; by regex&lt;/h2&gt;

&lt;p&gt;The latest addition sent by ccQpein is that &lt;code&gt;str:split&lt;/code&gt; now accepts a &lt;code&gt;:regex&lt;/code&gt; key argument to split by regular expressions. The functions &lt;code&gt;rsplit&lt;/code&gt; and &lt;code&gt;split-omit-nulls&lt;/code&gt; have it too.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:split &amp;quot;[,|;]&amp;quot; &amp;quot;foo,bar;baz&amp;quot; :regex t)
;; =&amp;gt; (&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot; &amp;quot;baz&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s handy for advent of code ;)&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;ppcre:split&lt;/code&gt;, this is the function that &lt;code&gt;str:split&lt;/code&gt;
relies on anyways, except that by default, &lt;code&gt;str:split&lt;/code&gt; ensures that the split argument is &lt;em&gt;not&lt;/em&gt; a regex. We need this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ppcre:split `(:sequence ,(string separator)) s …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(and eventually, we remove null elements if &lt;code&gt;:omit-nulls t&lt;/code&gt; was set)&lt;/p&gt;

&lt;h2 id=&#34;replace-by-regex&#34;&gt;replace by regex&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;str:replace-all&lt;/code&gt;, &lt;code&gt;str:replace-first&lt;/code&gt; and &lt;code&gt;str:replace-using&lt;/code&gt; got a &lt;code&gt;:regex&lt;/code&gt; keyword too:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:replace-all &amp;quot;(?i)fo+&amp;quot; &amp;quot;frob&amp;quot; &amp;quot;FOO bar FOO&amp;quot; :regex t)
;; =&amp;gt; &amp;quot;frob bar frob&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;the-ensure-functions&#34;&gt;The &lt;code&gt;ensure&lt;/code&gt; functions&lt;/h2&gt;

&lt;p&gt;These were added in March.&lt;/p&gt;

&lt;p&gt;The &amp;ldquo;ensure-&amp;rdquo; functions return a string that has the specified prefix or suffix, appended if necessary.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ensure&lt;/code&gt; encapsulates the other two.&lt;/p&gt;

&lt;h3 id=&#34;ensure-prefix-ensure-suffix-start-end-s&#34;&gt;ensure-prefix, ensure-suffix &lt;code&gt;(start/end s)&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Ensure that &lt;code&gt;s&lt;/code&gt; starts with &lt;code&gt;start/end&lt;/code&gt; (or ends with &lt;code&gt;start/end&lt;/code&gt;, respectively).&lt;/p&gt;

&lt;p&gt;Return a new string with its prefix (or suffix) added, if necessary.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:ensure-prefix &amp;quot;/&amp;quot; &amp;quot;abc/&amp;quot;) =&amp;gt; &amp;quot;/abc/&amp;quot; (a prefix was added)
;; and
(str:ensure-prefix &amp;quot;/&amp;quot; &amp;quot;/abc/&amp;quot;) =&amp;gt; &amp;quot;/abc/&amp;quot; (does nothing)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We also have a couple functions to find the prefixes or the suffixes, please see our README.&lt;/p&gt;

&lt;h3 id=&#34;ensure-wrapped-in-start-end-s&#34;&gt;ensure-wrapped-in &lt;code&gt;(start/end s)&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Ensure that &lt;code&gt;s&lt;/code&gt; both starts and ends with &lt;code&gt;start/end&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Return a new string with the necessary added bits, if required.&lt;/p&gt;

&lt;p&gt;It simply calls &lt;code&gt;str:ensure-suffix&lt;/code&gt; followed by &lt;code&gt;str:ensure-prefix&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See also &lt;code&gt;str:wrapped-in-p&lt;/code&gt; and &lt;code&gt;uiop:string-enclosed-p prefix s suffix&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:ensure-wrapped-in &amp;quot;/&amp;quot; &amp;quot;abc&amp;quot;) ;; =&amp;gt; &amp;quot;/abc/&amp;quot;  (added both a prefix and a suffix)
(str:ensure-wrapped-in &amp;quot;/&amp;quot; &amp;quot;/abc/&amp;quot;) ;; =&amp;gt; &amp;quot;/abc/&amp;quot; (does nothing)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;ensure-s-key-wrapped-in-prefix-suffix&#34;&gt;ensure &lt;code&gt;(s &amp;amp;key wrapped-in prefix suffix)&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This &lt;code&gt;str:ensure&lt;/code&gt; function looks for the following key parameters, in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:wrapped-in&lt;/code&gt;: if non nil, call &lt;code&gt;str:ensure-wrapped-in&lt;/code&gt;. This checks that &lt;code&gt;s&lt;/code&gt; both starts and ends with the supplied string or character.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:prefix&lt;/code&gt; and &lt;code&gt;:suffix&lt;/code&gt;: if both are supplied and non-nil, call &lt;code&gt;str:ensure-suffix&lt;/code&gt; followed by &lt;code&gt;str:ensure-prefix&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:prefix&lt;/code&gt;: call &lt;code&gt;str:ensure-prefix&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:suffix&lt;/code&gt;: call &lt;code&gt;str:ensure-suffix&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:ensure &amp;quot;abc&amp;quot; :wrapped-in &amp;quot;/&amp;quot;)  ;; =&amp;gt; &amp;quot;/abc/&amp;quot;
(str:ensure &amp;quot;/abc&amp;quot; :prefix &amp;quot;/&amp;quot;)  ;; =&amp;gt; &amp;quot;/abc&amp;quot;  =&amp;gt; no change, still one &amp;quot;/&amp;quot;
(str:ensure &amp;quot;/abc&amp;quot; :suffix &amp;quot;/&amp;quot;)  ;; =&amp;gt; &amp;quot;/abc/&amp;quot; =&amp;gt; added a &amp;quot;/&amp;quot; suffix.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These functions accept strings and characters:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:ensure &amp;quot;/abc&amp;quot; :prefix #\/)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;warn: if both &lt;code&gt;:wrapped-in&lt;/code&gt; and &lt;code&gt;:prefix&lt;/code&gt; (and/or &lt;code&gt;:suffix&lt;/code&gt;) are supplied together, &lt;code&gt;:wrapped-in&lt;/code&gt; takes precedence and &lt;code&gt;:prefix&lt;/code&gt; (and/or &lt;code&gt;:suffix&lt;/code&gt;) is ignored.&lt;/p&gt;

&lt;h2 id=&#34;char-bag-parameter-to-trim-trim-left-trim-right&#34;&gt;&lt;code&gt;:char-bag&lt;/code&gt; parameter to trim, trim-left, trim-right&lt;/h2&gt;

&lt;p&gt;This was added in January.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;str:trim&lt;/code&gt; removes all characters in &lt;code&gt;char-bag&lt;/code&gt; (default: whitespaces) at the beginning and end of &lt;code&gt;s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If supplied, &lt;code&gt;char-bag&lt;/code&gt; has to be a sequence (e.g. string or list of characters).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(str:trim &amp;quot;cdoooh&amp;quot; :char-bag (str:concat &amp;quot;c&amp;quot; &amp;quot;d&amp;quot; &amp;quot;h&amp;quot;)) =&amp;gt; &amp;quot;ooo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;fit-a-string-to-some-length&#34;&gt;fit a string to some length&lt;/h2&gt;

&lt;p&gt;This is older, it was added in February of 2022.&lt;/p&gt;

&lt;p&gt;Fit this string to the given length:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if it&amp;rsquo;s too long, shorten it (showing the &lt;code&gt;ellipsis&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;if it&amp;rsquo;s too short, add paddding (to the side &lt;code&gt;pad-side&lt;/code&gt;, adding the
character &lt;code&gt;pad-char&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As such, it accepts the same key arguments as &lt;code&gt;str:shorten&lt;/code&gt; and
&lt;code&gt;str:pad&lt;/code&gt;: &lt;code&gt;ellipsis&lt;/code&gt;, &lt;code&gt;pad-side&lt;/code&gt;, &lt;code&gt;pad-char&lt;/code&gt;…&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (str:fit 10 &amp;quot;hello&amp;quot; :pad-char &amp;quot;+&amp;quot;)
&amp;quot;hello+++++&amp;quot;

CL-USER&amp;gt; (str:fit 10 &amp;quot;hello world&amp;quot; :ellipsis &amp;quot;…&amp;quot;)
&amp;quot;hello wor…&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If, like me, you want to print a list of data as a table, see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-ansi-term/&#34;&gt;cl-ansi-term&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (ql:quickload &amp;quot;cl-ansi-term&amp;quot;)
CL-USER&amp;gt; (term:table &#39;((&amp;quot;name&amp;quot; &amp;quot;age&amp;quot; &amp;quot;email&amp;quot;)
              (&amp;quot;me&amp;quot; 7 &amp;quot;some@blah&amp;quot;)
              (&amp;quot;me&amp;quot; 7 &amp;quot;some@with-some-longer.email&amp;quot;))
             :column-width &#39;(10 4 20))
+---------+---+-------------------+
|name     |age|email              |
+---------+---+-------------------+
|me       |7  |some@blah          |
+---------+---+-------------------+
|me       |7  |some@with-some-l(…)|
+---------+---+-------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/telephil/cl-ascii-table/&#34;&gt;cl-ascii-table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (ql:quickload &amp;quot;cl-ascii-table&amp;quot;)
CL-USER&amp;gt; (let ((table (ascii-table:make-table &#39;(&amp;quot;Id&amp;quot; &amp;quot;Name&amp;quot; &amp;quot;Amount&amp;quot;) :header &amp;quot;Infos&amp;quot;)))
  (ascii-table:add-row table &#39;(1 &amp;quot;Bob&amp;quot; 150))
  (ascii-table:add-row table &#39;(2 &amp;quot;Joe&amp;quot; 200))
  (ascii-table:add-separator table)
  (ascii-table:add-row table &#39;(&amp;quot;&amp;quot; &amp;quot;Total&amp;quot; 350))
  (ascii-table:display table))

.---------------------.
|        Infos        |
+----+-------+--------+
| Id | Name  | Amount |
+----+-------+--------+
|  1 | Bob   |    150 |
|  2 | Joe   |    200 |
+----+-------+--------+
|    | Total |    350 |
+----+-------+--------+
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;fixed-string-case&#34;&gt;fixed &lt;code&gt;string-case&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;str:string-case&lt;/code&gt; macro was missing an implicit progn, so with more
than one s-expression in the clauses, it didn&amp;rsquo;t fail… but it didn&amp;rsquo;t work
as expected either.&lt;/p&gt;

&lt;h2 id=&#34;fixed-for-lispworks&#34;&gt;Fixed for LispWorks&lt;/h2&gt;

&lt;p&gt;Characters are named differently, like &lt;code&gt;#\NewLine&lt;/code&gt;. We are still awaiting input on &lt;a href=&#34;https://github.com/vindarel/cl-str/issues/99&#34;&gt;one issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We reimplemented &lt;code&gt;str:replace-using&lt;/code&gt; to fix it on LispWorks.&lt;/p&gt;

&lt;h2 id=&#34;misc&#34;&gt;Misc&lt;/h2&gt;

&lt;p&gt;We added type declaration e.g. for &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;join&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;str:ends-with-p&lt;/code&gt; now works with a character.&lt;/p&gt;

&lt;p&gt;Small breaking change: fixed &lt;code&gt;str:prefixp&lt;/code&gt; when used with a smaller prefix: &amp;ldquo;f&amp;rdquo; was not recognized as a prefix of &amp;ldquo;foobar&amp;rdquo; and &amp;ldquo;foobuz&amp;rdquo;, only &amp;ldquo;foo&amp;rdquo; was. Now it is fixed. Same for &lt;code&gt;str:suffixp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We added &lt;code&gt;str:ascii-p&lt;/code&gt; and &lt;code&gt;str:ascii-char-p&lt;/code&gt; (in 2021).&lt;/p&gt;

&lt;p&gt;More functions now work with characters as well.&lt;/p&gt;

&lt;p&gt;We sped up &lt;code&gt;str:join&lt;/code&gt; (measured: 4x). We use &lt;code&gt;with-output-to-string&lt;/code&gt; and a loop instead of &lt;code&gt;format&lt;/code&gt;&amp;rsquo;s iteration directive.&lt;/p&gt;

&lt;p&gt;We use uninterned symbols in defpackage.&lt;/p&gt;

&lt;p&gt;We deprecated predicates ending with &amp;ldquo;?&amp;rdquo; (but they are still there).&lt;/p&gt;

&lt;p&gt;We made casing-functions consistent to inbuilt cl casing functions (we use &lt;code&gt;cl-change-case&lt;/code&gt;, but the functions also allow symbols and characters (not only strings) and return NIL when given NIL).&lt;/p&gt;

&lt;p&gt;We added &lt;code&gt;:ignore-case&lt;/code&gt; to &lt;code&gt;str:count-substring&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We switched the testing framework from prove to fiveam (that was grunt work by the new maintainer yay o/ )&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;That&amp;rsquo;s it, thanks again for helping make this lil&amp;rsquo; lib useful since day 1.&lt;/p&gt;

&lt;p&gt;The &amp;ldquo;str&amp;rdquo; library defines many more functions. Look at our table of content on the README: &lt;a href=&#34;https://github.com/vindarel/cl-str&#34;&gt;https://github.com/vindarel/cl-str&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install it with&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;str&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Common Lisp on the web: enrich your stacktrace with request and session data</title>
      <link>/blog/common-lisp-on-the-web-enrich-your-stacktrace-with-request-and-session-data/</link>
      <pubDate>Fri, 13 Oct 2023 16:51:07 +0200</pubDate>
      
      <guid>/blog/common-lisp-on-the-web-enrich-your-stacktrace-with-request-and-session-data/</guid>
      <description>

&lt;p&gt;A short post to show the usefulness of &lt;a href=&#34;https://github.com/mmontone/hunchentoot-errors&#34;&gt;Hunchentoot-errors&lt;/a&gt; and to thank Mariano again.&lt;/p&gt;

&lt;p&gt;This library adds the current request and session data to your stacktrace, either in the REPL (base case) or in the browser.&lt;/p&gt;

&lt;p&gt;TLDR;&lt;/p&gt;

&lt;p&gt;Use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; (ql:quickload &amp;quot;hunchentoot-errors)
;;
;; We also use easy-routes: (ql:quickload &amp;quot;easy-routes&amp;quot;)

(defclass acceptor (easy-routes:easy-routes-acceptor hunchentoot-errors:errors-acceptor)
  ()
  (:documentation &amp;quot;Our Hunchentoot acceptor that uses easy-routes and hunchentoot-errors, for easier route definition and enhanced stacktraces with request and session data.&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then &lt;code&gt;(make-instance &#39;acceptor :port 4242)&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&#34;base-case&#34;&gt;Base case&lt;/h1&gt;

&lt;p&gt;Imagine you have a bug in your route:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(easy-routes:defroute route-card-page (&amp;quot;/card/:slug&amp;quot; :method :GET :decorators ((@check-roles admin-role)))
    (&amp;amp;get debug)
  (error &amp;quot;oh no&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you access &lt;code&gt;localhost:4242/card/100-common-lisp-recipes&lt;/code&gt;, you will see this in the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[2023-10-13 16:48:21 [ERROR]] oh no
Backtrace for: #&amp;lt;SB-THREAD:THREAD &amp;quot;hunchentoot-worker-127.0.0.1:53896&amp;quot; RUNNING {10019A21A3}&amp;gt;
0: (TRIVIAL-BACKTRACE:PRINT-BACKTRACE-TO-STREAM #&amp;lt;SB-IMPL::CHARACTER-STRING-OSTREAM {1006E9ED43}&amp;gt;)
1: (HUNCHENTOOT::GET-BACKTRACE)
2: ((FLET &amp;quot;H0&amp;quot; :IN HUNCHENTOOT:HANDLE-REQUEST) #&amp;lt;SIMPLE-ERROR &amp;quot;oh no&amp;quot; {1006E9EBE3}&amp;gt;)
3: (SB-KERNEL::%SIGNAL #&amp;lt;SIMPLE-ERROR &amp;quot;oh no&amp;quot; {1006E9EBE3}&amp;gt;)
4: (ERROR &amp;quot;oh no&amp;quot;)
5: (MYWEBAPP/WEB::ROUTE-CARD-PAGE &amp;quot;100-common-lisp-recipes&amp;quot;)
6: ((:METHOD HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST (EASY-ROUTES:EASY-ROUTES-ACCEPTOR T)) #&amp;lt;MYWEBAPP/WEB::ACCEPTOR (host *, port 4242)&amp;gt; #&amp;lt;HUNCHENTOOT:REQUEST {1006C55F33}&amp;gt;) [fast-method]
7: ((:METHOD HUNCHENTOOT:HANDLE-REQUEST (HUNCHENTOOT:ACCEPTOR HUNCHENTOOT:REQUEST)) #&amp;lt;MYWEBAPP/WEB::ACCEPTOR (host *, port 4242)&amp;gt; #&amp;lt;HUNCHENTOOT:REQUEST {1006C55F33}&amp;gt;) [fast-method]
[…]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And, by default, you see a basic error message in the browser:&lt;/p&gt;



&lt;img src=&#34;/images/hunchentoot-error.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;h1 id=&#34;show-errors&#34;&gt;Show errors&lt;/h1&gt;

&lt;p&gt;Set this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf hunchentoot:*show-lisp-errors-p* t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can see a backtrace in the browser window, which is of course
super useful during development:&lt;/p&gt;



&lt;img src=&#34;/images/hunchentoot-show-error.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;BTW, if you unset this one:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf hunchentoot:*show-lisp-backtraces-p* nil)  ;; t by default
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will see the error message, but not the backtrace:&lt;/p&gt;



&lt;img src=&#34;/images/hunchentoot-error-no-backtrace.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;And I remind you that if you set &lt;code&gt;*catch-errors-p*&lt;/code&gt; to nil, you&amp;rsquo;ll get the debugger inside your IDE (Hunchentoot will &lt;em&gt;not&lt;/em&gt; catch the errors, and will pass it to you).&lt;/p&gt;

&lt;h1 id=&#34;now-with-request-and-session-data&#34;&gt;Now with request and session data&lt;/h1&gt;

&lt;p&gt;Now create your server with our new acceptor, inheriting hunchentoot-errors.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll see the current request and session paramaters both in the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[…]
19: (SB-THREAD::NEW-LISP-THREAD-TRAMPOLINE #&amp;lt;SB-THREAD:THREAD &amp;quot;hunchentoot-worker-127.0.0.1:48756&amp;quot; RUNNING {100AAAFC43}&amp;gt; NIL #&amp;lt;CLOSURE (LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS) {100AAAFBEB}&amp;gt; NIL)
20: (&amp;quot;foreign function: call_into_lisp&amp;quot;)
21: (&amp;quot;foreign function: new_thread_trampoline&amp;quot;)

HTTP REQUEST:
  uri: /card/100-common-lisp-recipes
  method: GET
  headers:
    HOST: localhost:4242
    USER-AGENT: Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0
    ACCEPT: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
    ACCEPT-LANGUAGE: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
    ACCEPT-ENCODING: gzip, deflate, br
    DNT: 1
    CONNECTION: keep-alive
    COOKIE: &amp;quot;...&amp;quot;
    UPGRADE-INSECURE-REQUESTS: 1
    SEC-FETCH-DEST: document
    SEC-FETCH-MODE: navigate
    SEC-FETCH-SITE: none
    SEC-FETCH-USER: ?1

SESSION:
  :USER: #&amp;lt;MYWEBAPP.MODELS:USER {100EA8C753}&amp;gt;

127.0.0.1 - [2023-10-13 17:32:18] &amp;quot;GET /card/100-common-lisp-recipes HTTP/1.1&amp;quot; 500 5203 &amp;quot;-&amp;quot; &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and in the browser:&lt;/p&gt;



&lt;img src=&#34;/images/hunchentoot-error-with-request.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;(notice the &lt;code&gt;#&amp;lt;USER {…}&amp;gt;&lt;/code&gt; at the bottom? You&amp;rsquo;ll need a commit from today to see it, instead of &lt;code&gt;#&lt;/code&gt; only)&lt;/p&gt;

&lt;h1 id=&#34;final-words&#34;&gt;Final words&lt;/h1&gt;

&lt;p&gt;These Hunchentoot variables were kinda explained on the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/web.html#hunchentoot-5&#34;&gt;Cookbook/web.html&lt;/a&gt;, I&amp;rsquo;ll augment that.&lt;/p&gt;

&lt;p&gt;Clack users can use the &lt;code&gt;clack-errors&lt;/code&gt; midleware.&lt;/p&gt;



&lt;img src=&#34;https://vindarel.github.io/cl-cookbook/assets/clack-errors.png&#34; style=&#34;max-width: 100%&#34;/&gt;



&lt;p&gt;Who wants to send a PR for colourful stacktraces?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp-libraries.readthedocs.io/hunchentoot/&#34;&gt;Common Lisp Read the Docs: Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#web-frameworks&#34;&gt;awesome-cl#web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>I published 17 videos about Common Lisp macros - learn Lisp with a code-first tutorial 🎥 ⭐</title>
      <link>/blog/17-new-videos-on-common-lisp-macros/</link>
      <pubDate>Fri, 15 Sep 2023 17:07:23 +0200</pubDate>
      
      <guid>/blog/17-new-videos-on-common-lisp-macros/</guid>
      <description>

&lt;p&gt;For those who don&amp;rsquo;t know and who didn&amp;rsquo;t see the banner :D I am creating a Common Lisp course on the Udemy platform (with complementary videos on Youtube). I wanted to do something different and complementary than writing on the Cookbook.&lt;/p&gt;

&lt;p&gt;I worked on new videos this summer and I just finished editing the subtitles. I have added &lt;strong&gt;17 videos&lt;/strong&gt; (worth 1h30+ of code-driven content) &lt;strong&gt;about Common Lisp macros&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER&#34;&gt;We cover a lot of content&lt;/a&gt;: quote, backquote and comma, &amp;ldquo;,@&amp;rdquo;, comparison with C macros, comparison with functions, GENSYM and variable capture, useful patterns (call-with…), compile-time computing, read-time evaluation… (full summary below)&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER&#34;&gt;&lt;img src=&#34;/announce.svg&#34; alt=&#34;New: 17 videos to learn Lisp macros&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find the course here: &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER&#34;&gt;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER&lt;/a&gt; (various videos are free to watch, so you can judge, and learn a couple things) (I can send free links to students, plz PM)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I recorded the last one, about the MACROSTEP tool, inside the &lt;strong&gt;Lem editor&lt;/strong&gt;. It&amp;rsquo;s short, you should have a look at how this new editor looks like. (I&amp;rsquo;m very excited about it. Did I say I started develop a Magit-like plugin for it?)&lt;/p&gt;

&lt;h2 id=&#34;who-is-this-course-for&#34;&gt;Who is this course for?&lt;/h2&gt;

&lt;p&gt;The whole course is for beginners in Lisp, although not total beginners in programming. This chapter is, logically, a bit more difficult than the others. If you didn&amp;rsquo;t write small Common Lisp programs yet, be gentle with yourself and stop if you don&amp;rsquo;t understand. (you can ask questions in the Udemy forum, of course) In your case I would advise to watch the introductory one, the comparison with C macros, the video on QUOTE, the &amp;ldquo;functions VS macros&amp;rdquo; one, and then carry on at your rhythm. Be sure to work on the previous chapters before tackling this one.&lt;/p&gt;

&lt;h2 id=&#34;content&#34;&gt;Content&lt;/h2&gt;

&lt;p&gt;This is what we see on the topic of macros. For a full overview of the
course, what I want to do next (if you subscribe now, you&amp;rsquo;ll get
new content for the same price) and read others&amp;rsquo; feedback, see &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;its GitHub project
page&lt;/a&gt;
(there are six more chapters including getting started, functions,
iteration, condition handling…).&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#content&#34;&gt;Content&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#71-a-quick-intro-free-preview&#34;&gt;7.1 A quick intro (&lt;strong&gt;FREE PREVIEW&lt;/strong&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#72-a-comparison-with-c-macros-free-preview&#34;&gt;7.2. A comparison with C macros (&lt;strong&gt;FREE PREVIEW&lt;/strong&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#73-quote-free-preview&#34;&gt;7.3 QUOTE (&lt;strong&gt;FREE PREVIEW&lt;/strong&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#74-backquote-and-comma&#34;&gt;7.4 Backquote and comma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#75-how-to-spot-you-are-using-a-macro&#34;&gt;7.5 How to spot you are using a macro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#76-functions-vs-macros&#34;&gt;7.6 Functions vs macros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#77-comma-splice--the-third-most-important-macro-mechanism&#34;&gt;7.7 COMMA SPLICE ,@ the third most important macro mechanism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#78-body-and-other-macro-parameters-our-second-macro-model&#34;&gt;7.8 &amp;amp;body and other macro parameters. Our second macro model.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#79-putting-this-together-with-echo-macro-macroexpand-in-use&#34;&gt;7.9 Putting this together: with-echo macro. Macroexpand in use.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#710-gensym--the-simple-fix-to-the-most-dangerous-macros-gotcha&#34;&gt;7.10 GENSYM -the simple fix to the most dangerous macros gotcha&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#711-call-with-pattern-simplifying-macros&#34;&gt;7.11 CALL-WITH pattern: simplifying macros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#712-compile-time-computing&#34;&gt;7.12 Compile time computing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#713-lists-vs-ast&#34;&gt;7.13 Lists VS AST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#714-two-example-macros-for-compile-time-computing&#34;&gt;7.14 Two example macros for compile-time computing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#715-symbol-macro&#34;&gt;7.15 SYMBOL-MACRO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#716-read-time-evaluation-with-&#34;&gt;7.16 Read-time evaluation with #.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#717-editor-tool-macrostep-free-preview-lem-demo&#34;&gt;7.17 EDITOR TOOL: macrostep &lt;strong&gt;(FREE PREVIEW, Lem demo)&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#thanks&#34;&gt;Thanks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h3 id=&#34;7-1-a-quick-intro-free-preview&#34;&gt;7.1 A quick intro (&lt;strong&gt;FREE PREVIEW&lt;/strong&gt;)&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Macros do not evaluate their arguments and expand to new code at compile time. What does that mean? A quick intro before diving deeper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-2-a-comparison-with-c-macros-free-preview&#34;&gt;7.2. A comparison with C macros (&lt;strong&gt;FREE PREVIEW&lt;/strong&gt;)&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Lisp macros are NOT manipulating text, unlike C. Text leads to many unnecessary problems. We have a fun tour of a trivial need yet complicated issue in C that is easily done in Common Lisp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-3-quote-free-preview&#34;&gt;7.3 QUOTE (&lt;strong&gt;FREE PREVIEW&lt;/strong&gt;)&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;QUOTE does not evaluate its argument.&lt;/p&gt;

&lt;p&gt;What we see: how to use QUOTE outside macros. Data takes the shape of code. We pair it with eval and we go full circle. We introduce the need to extrapolate values inside a quote.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-4-backquote-and-comma&#34;&gt;7.4 Backquote and comma&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: how we extrapolate variable values. How they can help create data structures. Real world examples.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-5-how-to-spot-you-are-using-a-macro&#34;&gt;7.5 How to spot you are using a macro&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Four tips to recognize if you are using a function or a macro, and why it matters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-6-functions-vs-macros&#34;&gt;7.6 Functions vs macros&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Macros do NOT replace functions!&lt;/p&gt;

&lt;p&gt;What we see: they are not higher-level functions. The subtle but logic need to re-compile functions using macros.&lt;/p&gt;

&lt;p&gt;Introducing MACROEXPAND.&lt;/p&gt;

&lt;p&gt;Keeping compile-time computing in mind (more on that later). A look at a function&amp;rsquo;s disassembly. So… you might not need a macro yet ;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-7-comma-splice-the-third-most-important-macro-mechanism&#34;&gt;7.7 COMMA SPLICE ,@ the third most important macro mechanism&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: when use it, understanding the common error messages, passing body forms to our macro. Our first macro model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-8-body-and-other-macro-parameters-our-second-macro-model&#34;&gt;7.8 &amp;amp;body and other macro parameters. Our second macro model.&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: how &amp;amp;body differs to &amp;amp;rest. Macro parameters: lots of possibilities, but some conventions carry meaning. Our own DOLIST macro. Our second macro model you can follow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-9-putting-this-together-with-echo-macro-macroexpand-in-use&#34;&gt;7.9 Putting this together: with-echo macro. Macroexpand in use.&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We build our first macro with backquote and comma-splice, even a quote followed by a comma. We use macroexpand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-10-gensym-the-simple-fix-to-the-most-dangerous-macros-gotcha&#34;&gt;7.10 GENSYM -the simple fix to the most dangerous macros gotcha&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: what is variable capture and how to avoid it. Writing our own REPEAT macro. A little discussion about Common Lisp VS Scheme macros. GENSYM can be used outside macros too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this point you know enough to write all common macros. See the exercises for easy and not-so-easy ones.&lt;/p&gt;

&lt;h3 id=&#34;7-11-call-with-pattern-simplifying-macros&#34;&gt;7.11 CALL-WITH pattern: simplifying macros&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We saw there can be subtle pitfalls when we write a macro. This pattern allows to offload most of the work to a function, which presents many advantages. We demo with our REPEAT macro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-12-compile-time-computing&#34;&gt;7.12 Compile time computing&lt;/h3&gt;

&lt;p&gt;When writing macros, we have the full power of Common Lisp at compile time. This gives great tools to the developer: early type errors and warnings, faster runtime.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: a simple example, writing a scientific macro for conversion of unit at compile time, existing libraries for that, introduction to dispatching macro characters and reader macros.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-13-lists-vs-ast&#34;&gt;7.13 Lists VS AST&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;What we see: other languages don&amp;rsquo;t have macros but can manipulate Abstract Syntax Trees. Code as lists of symbols is not the same, we would need a third-party library to manipulate a Lisp AST proper. This doesn&amp;rsquo;t prevent us to develop crazy macros though, see this library adding Haskell-like type checking on top of Common Lisp, in pure CL macros.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-14-two-example-macros-for-compile-time-computing&#34;&gt;7.14 Two example macros for compile-time computing&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;defstar allows to specify a function&amp;rsquo;s arguments&amp;rsquo; types, Serapeum&amp;rsquo;s ecase-of does exhaustiveness type checking. At compile time, of course.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-15-symbol-macro&#34;&gt;7.15 SYMBOL-MACRO&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A symbol macro is not your everyday Lisp development tool, but it expands your toolbet. Again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-16-read-time-evaluation-with&#34;&gt;7.16 Read-time evaluation with #.&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Macros occur at compile-time. But Common Lisp blurs the lines between read time, compile time and run time. This allows to execute code at READ time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;7-17-editor-tool-macrostep-free-preview-lem-demo&#34;&gt;7.17 EDITOR TOOL: macrostep &lt;strong&gt;(FREE PREVIEW, Lem demo)&lt;/strong&gt;&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Macrostep is an editor extension that helps understand our macro expansions. It is only available in Sly and Lem. We demo with the Lem editor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;thanks&#34;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;Thanks for your support, it does make a difference (I am self employed,
I don&amp;rsquo;t earn millions and I&amp;rsquo;d love to spend *even more time* on CL
resources and projects). If you want to learn what I do for the Lisp
community and why you should buy my course, &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;read more on
Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My &lt;a href=&#34;https://www.youtube.com/@vindarel&#34;&gt;complementary Lisp videos are on Youtube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don&amp;rsquo;t hesitate to share the link with a friend or a colleague :) Thanks, and happy lisping.&lt;/p&gt;

&lt;p&gt;A demo about web development has been recorded and is coming.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;ps: we just got &lt;a href=&#34;https://github.com/ciel-lang/CIEL/&#34;&gt;a Dockerfile for CIEL&lt;/a&gt;, which is then easier to test, thanks to a &amp;ldquo;student&amp;rdquo; of my course. Thanks,
&lt;a href=&#34;https://github.com/themarcelor/&#34;&gt;@themarcelor&lt;/a&gt;. It will be on Dockerhub in due time.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER&#34;&gt;&lt;img src=&#34;/tweet-2023-07.png&#34; alt=&#34;&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Udemy course by @vindarel is &lt;strong&gt;the&lt;/strong&gt; best introductory material for a fast and practical intro to Common Lisp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(thanks &amp;lt;3)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A wonderful course for someone with cursory knowledge of lisp. I&amp;rsquo;ve dipped my feet many times now, but always struggled to wrap my head around everything. This course really helped give me greater confidence in how to start a project. I really enjoyed the focus on having an executable early. The Lisp-2 reveal was beautiful and made me finally understand the difference. Thanks a lot!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simon, August of 2023. (thanks &amp;lt;3 )&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pretty GUIs now: nodgui comes with a pre-installed nice looking theme</title>
      <link>/blog/nodgui-now-has-a-nice-looking-theme-by-default/</link>
      <pubDate>Thu, 01 Jun 2023 19:03:35 +0200</pubDate>
      
      <guid>/blog/nodgui-now-has-a-nice-looking-theme-by-default/</guid>
      <description>

&lt;p&gt;Being able to load a custom theme is great, but it would be even
better if we didn&amp;rsquo;t have to manually install one.&lt;/p&gt;

&lt;p&gt;Well, recent changes in &lt;a href=&#34;https://notabug.org/cage/nodgui&#34;&gt;nodgui&lt;/a&gt; from
yesterday and today just dramatically improved the GUI situation for
Common Lisp[0].&lt;/p&gt;

&lt;h2 id=&#34;nodgui-now-ships-the-yaru-theme&#34;&gt;nodgui now ships the yaru theme&lt;/h2&gt;

&lt;p&gt;@cage commited the &lt;a href=&#34;https://ttkthemes.readthedocs.io/en/latest/themes.html#yaru&#34;&gt;Yaru theme from ttkthemes&lt;/a&gt; in nodgui&amp;rsquo;s repository, and we added QoL improvements. To use it, now you can simply do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-nodgui ()
  (use-theme &amp;quot;yaru&amp;quot;)
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-nodgui (:theme &amp;quot;yaru&amp;quot;)
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf nodgui:*default-theme* &amp;quot;yaru&amp;quot;)
(with-nodgui ()
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yaru looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-yaru.png&#34; alt=&#34;&amp;quot;yaru theme list box and buttons&amp;quot;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/treeview-yaru.png&#34; alt=&#34;&amp;quot;yaru theme treeview&amp;quot;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://imgur.com/I4EYDSA.png&#34; alt=&#34;&amp;quot;yaru theme&amp;quot;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;No, it isn&amp;rsquo;t native, but it doesn&amp;rsquo;t look like the 50s either.&lt;/p&gt;

&lt;p&gt;See my &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/pretty-gui-in-common-lisp-with-nodgui-tk-themes/&#34;&gt;previous post&lt;/a&gt; for more themes, screenshots and instructions to load a third-party theme. Forest Light is nice too!&lt;/p&gt;

&lt;h2 id=&#34;try-the-demos&#34;&gt;Try the demos&lt;/h2&gt;

&lt;p&gt;Try the demos with this theme:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf nodgui:*default-theme* &amp;quot;yaru&amp;quot;)
(nodgui.demo:demo)
;; or
(nodgui.demo:demo :theme &amp;quot;yaru&amp;quot;)
;; a precise demo
(nodgui.demo::demo-widget :theme &amp;quot;yaru&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;themes-directory&#34;&gt;Themes directory&lt;/h2&gt;

&lt;p&gt;@cage also made it easier to load a theme.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have added the special variable &lt;code&gt;*themes-directory*&lt;/code&gt; (default is the directory themes under the directory where the asdf system is) where the library looks for themes.&lt;/p&gt;

&lt;p&gt;Each theme must be placed in their own directory as a subdirectory of the aforementioned variable, the name of the directory must be the name of the theme; moreover the name of the TCL file that specify the file must be named as the same of the theme with the extension &amp;ldquo;tcl&amp;rdquo; appended&lt;/p&gt;

&lt;p&gt;For example, the theme &amp;ldquo;foo&amp;rdquo; has to be: &amp;ldquo;foo/foo.tcl&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Provided these conditions are met using a new theme should be as simple as type &lt;code&gt;(nodgui:use-theme &amp;quot;foo&amp;quot;)&lt;/code&gt;, without &lt;code&gt;(nodgui: eval-tcl-file)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Otherwise, just clone a theme repository somewhere, and call&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(eval-tcl-file &amp;quot;path/to/the/theme.tcl&amp;quot;)
(use-theme &amp;quot;theme&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I can very well imagine using small GUI tools built in Tk and this theme. I&amp;rsquo;ll have to try nogui&amp;rsquo;s auto-complete widget too. If you do build a little something, please share, it will help and inspire me and the ones after you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://peterlane.netlify.app/ltk-examples/&#34;&gt;https://peterlane.netlify.app/ltk-examples/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;@cage announces new releases on Mastodon. &lt;code&gt;@cage@stereophonic.space&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;[0]: be more grandiose if you can.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pretty GUI in Common Lisp with nodgui&#39;s Tk themes</title>
      <link>/blog/pretty-gui-in-common-lisp-with-nodgui-tk-themes/</link>
      <pubDate>Sat, 27 May 2023 00:22:04 +0200</pubDate>
      
      <guid>/blog/pretty-gui-in-common-lisp-with-nodgui-tk-themes/</guid>
      <description>&lt;p&gt;Do you think Tcl/Tk GUIs are doomed to look outdated?&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/mediaplayer.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Fear not!&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-adapta.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-yaru.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-forest-light.png&#34; alt=&#34;Forest light theme&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-aquativo.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-breeze.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-clearlooks.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-radiance.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/media-lightbrown.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;A treeview widget:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/treeview-forest.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/ltk-tests/master/treeview-yaru.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The official example of &lt;a href=&#34;https://github.com/rdbende/Forest-ttk-theme&#34;&gt;Forest Light&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/rdbende/Forest-ttk-theme/master/Forest-light%20screenshot.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;https://ttkthemes.readthedocs.io/en/latest/themes.html&#34;&gt;ttkthemes gallery&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plus, Tk itself has a little choice of built-in themes:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://lispcookbook.github.io/cl-cookbook/assets/gui/ltk-on-macos.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;We can use these themes with &lt;a href=&#34;https://notabug.org/cage/nodgui&#34;&gt;nodgui&lt;/a&gt;, the Ltk fork.&lt;/p&gt;

&lt;p&gt;In June of 2020, @cage added a little function to load a .tcl file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun eval-tcl-file (file-path)
  &amp;quot;This function will feed the TCL interpreter with the contents
   of the file `path&#39;.
   Please, as this function will load  and execute a script, ensure to
   load files only from trusted sources otherwise severe security problem
   may arise.&amp;quot;
  (assert (stringp file-path))
  (format-wish &amp;quot;source {~a}&amp;quot; file-path))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As a consequence, we can load a .tcl script that defines a theme, and use it. Themes generally consist of a .tcl script and a directory of png or gif images (when images are not defined in-line).&lt;/p&gt;

&lt;p&gt;Considering we cloned the ttkthemes repo locally:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (with-nodgui ()
    (eval-tcl-file &amp;quot;ttkthemes/ttkthemes/png/yaru/yaru.tcl&amp;quot;)
    (use-theme &amp;quot;yaru&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and that&amp;rsquo;s all there is to it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;For now, some themes are not supported. Scalable themes are not
supported, the .gif based themes of ttkthemes won&amp;rsquo;t load (the &amp;ldquo;scid&amp;rdquo;
and &amp;ldquo;smog&amp;rdquo; themes in ttkthemes, the &lt;a href=&#34;https://github.com/rdbende/Sun-Valley-ttk-theme&#34;&gt;Sun Valley
theme&lt;/a&gt; didn&amp;rsquo;t
work). This could change when &lt;code&gt;tksvg&lt;/code&gt; lands in Debian (or maybe, if
you install it yourself? I didn&amp;rsquo;t try), or with the next release of
Tcl/Tk that will include SVG support (read
&lt;a href=&#34;https://notabug.org/cage/nodgui/issues/13&#34;&gt;#13&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Frankly, that was a great news of the day. Yes, I think some themes
are pleasant to the eyes! This makes me want to use little Tk UIs here
and there.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/vindarel/ltk-tests/blob/master/musicplayer-nodgui.lisp&#34;&gt;Here&amp;rsquo;s the code&lt;/a&gt; for the little media player of the screenshots. It is based on &lt;a href=&#34;https://peterlane.netlify.app/ltk-examples/&#34;&gt;Peter Lane&amp;rsquo;s extensive examples&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Kuddos to @cage o/&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>i18n in my Lisp web app with Djula templates and gettext</title>
      <link>/blog/i18n-in-my-lisp-web-app-with-djula-templates-and-gettext/</link>
      <pubDate>Mon, 08 May 2023 14:01:34 +0200</pubDate>
      
      <guid>/blog/i18n-in-my-lisp-web-app-with-djula-templates-and-gettext/</guid>
      <description>

&lt;p&gt;I finally added translations to my Lisp web app \o/&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/djula-gettext.png&#34; alt=&#34;A welcome screen with text translated to french, yiha!&#34; width=&#34;750&#34;/&gt;&lt;/p&gt;

&lt;p&gt;I wanted to do it with &lt;code&gt;gettext&lt;/code&gt; and Djula templates. There seemed to
be some support for this, but it turned out… not
straightforward. After two failed attempts, I decided to offer a
little 90 USD bounty for the task (I announced it on the project&amp;rsquo;s
issues and on Discord, watch them out for future bounties ;) ).&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fstamour/&#34;&gt;@fstamour&lt;/a&gt; took the challenge and is
the person I&amp;rsquo;ll be eternally grateful for :D He kindly set up
everything, answered my questions and traced down annoying bugs. BTW,
I recommend you have a look at his ongoing
&lt;a href=&#34;https://github.com/fstamour/breeze/&#34;&gt;breeze&lt;/a&gt; project (towards refactoring tools for CL) and
&lt;a href=&#34;https://github.com/fstamour/local-gitlab&#34;&gt;local-gitlab&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Many thanks go as usual to @mmontone for incorporating changes to Djula after our feedback. Here&amp;rsquo;s Djula documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mmontone.github.io/djula/djula/Internationalization.html#Backends&#34;&gt;https://mmontone.github.io/djula/djula/Internationalization.html#Backends&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Djula&amp;rsquo;s gettext backend is based of the &lt;a href=&#34;https://github.com/rotatef/gettext/issues/3&#34;&gt;rotatef/gettext&lt;/a&gt; library. It worked fine. I left some feedback there anyways.&lt;/p&gt;

&lt;h2 id=&#34;why-gettext&#34;&gt;Why gettext&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/gettext/manual/gettext.html#SEC_Contents&#34;&gt;GNU gettext&lt;/a&gt;
is the canonical tool to bring translations to software
projects. Using it ensures we have access to its range of localization
features and it unlocks the possibility to use modern web-based
translation tools (like Weblate), according you have the pretention to have
external translators for your project.&lt;/p&gt;

&lt;p&gt;I looked at other Lisp libraries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://notabug.org/cage/cl-i18n&#34;&gt;cl-i18n&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;an i18n library. Load translations from GNU gettext text or binary files or from its native format. Localisation helpers of plural forms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may ship improvements uppon gettext, but @fstamour ultimately chose gettext over it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I ended up with so much less code with gettext than with cl-i18n and I found gettext&amp;rsquo;s code much easier to read if the documentation was lacking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(BTW, @cage has been really helpful in answering many questions, hello o/ ) He explained:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Seems that the library you pointed out does not support any files but MO (binary) files. cl-18n can parse a couple more of formats like its own and include an extractor for translatable strings in source files, so can be used without any of the gettext toolchain. But they address the same problem in more or less the same way. :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dkochmanski/translate&#34;&gt;translate&lt;/a&gt; also is not
gettext-compatible, it has a function to find missing translations,
it got a Djula backend last April. Look, it is this easy to add a
backend:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; translation-translate.lisp
(in-package :djula)

(defmethod backend-translate ((backend (eql :translate)) string language &amp;amp;rest args)
  (apply #&#39;translate:translate string language args))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/cl-locale/&#34;&gt;cl-locale&lt;/a&gt;, a &amp;ldquo;Simple i18n
library for Common Lisp&amp;rdquo;, works with hand-written dictionaries, it
also is not gettext-compatible, it has a Djula backend but it has no
tool to collect all the translatable strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Djula is a very nice templating library that works with HTML
templates, much like Django templates. It has support for 2
translation backends, although I found it hard to start with. It
should be better now, but you&amp;rsquo;re welcome to improve things further.&lt;/p&gt;

&lt;p&gt;To translate a string in a template, we enclose it between &lt;code&gt;{_ _}&lt;/code&gt; marks like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;p&amp;gt; {_ &amp;quot;Please login to continue&amp;quot; _} &amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We will setup what&amp;rsquo;s necessary to collect those strings and handle them with &lt;code&gt;gettext&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;extracting-strings-from-lisp-source-files&#34;&gt;Extracting strings from .lisp source files&lt;/h2&gt;

&lt;p&gt;We need to extract strings from .lisp source files and from HTML templates.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;xgettext&lt;/code&gt; already allows to collect strings for a lot of
languages. It understands the Lisp syntax, we only need to tell it
what is the marker used to mark strings to translate. We will use the
underscore function, as it is the convention for many languages out
there:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(_ &amp;quot;welcome&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We have to setup the gettext library:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (gettext:textdomain) &amp;quot;bookshops&amp;quot;)
;;                          ^^ a meaningful name for gettext&#39;s catalogue.

(gettext:setup-gettext #.*package* &amp;quot;bookshops&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates new functions under the hood in the current package:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setup-gettext (package default-domain)
  (setf package (find-package package))
  (check-type default-domain string)
  `(progn
     (defun ,(intern &amp;quot;GETTEXT&amp;quot; package) (msgid &amp;amp;optional domain category locale)
       (gettext* msgid (or domain ,default-domain) category locale))
     (defun ,(intern &amp;quot;_&amp;quot; package) (msgid &amp;amp;optional domain category locale)
       (gettext* msgid (or domain ,default-domain) category locale))
     (defun ,(intern &amp;quot;NGETTEXT&amp;quot; package) (msgid1 msgid2 n &amp;amp;optional domain category locale)
       (ngettext* msgid1 msgid2 n (or domain ,default-domain) category locale))
     (defun ,(intern &amp;quot;N_&amp;quot; package) (msgid)
       msgid)
     (defun ,(intern &amp;quot;CATALOG-META&amp;quot; package) (&amp;amp;optional domain category locale)
       (catalog-meta* (or domain ,default-domain) category locale))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So yes, it creates the &lt;code&gt;_&lt;/code&gt; function. It does this in a macro so that
the function will populate our catalogue by default. You can now export it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defpackage :bookshops.i18n
  (:use :cl)
  (:import-from :gettext #:*current-locale*)
  (:export
   #:_
   #:n_
   #:*current-locale*
   #:list-loaded-locales
   #:set-locale
   #:with-locale
   #:update-djula.pot)
  (:documentation &amp;quot;Internationalisation utilities&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can now call &lt;code&gt;xgettext&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;xgettext --language=lisp --from-code=UTF-8 --keyword=_ --output=locale/ie.pot --sort-output
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the &lt;code&gt;--keyword&lt;/code&gt; argument (&lt;code&gt;-K&lt;/code&gt;) tells it we are using the underscore. Hey, we also want to collect the &lt;code&gt;N_&lt;/code&gt; ones (for &lt;code&gt;ngettext&lt;/code&gt;, it handles grammatical forms that depend on a number (typically, plurals)):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;xgettext -k_ -kN_
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, now we want to find all our .lisp sources and extract strings from them all. We&amp;rsquo;ll search them with a call to &lt;code&gt;find . -iname &amp;quot;*.lisp&amp;quot; …&lt;/code&gt;. You have an example in Djula&amp;rsquo;s doc, here&amp;rsquo;s how we did (ahem, how Francis did) with a Makefile target:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-Makefile&#34;&gt;# List .lisp files under our src/ directory, unless they contain a #
SRC := $(shell find src/ -name &#39;*.lisp&#39; -a ! -name &#39;*\#*&#39;)
HTML := $(shell find src/ -name &#39;*.html&#39; -a ! -name &#39;*\#*&#39;)
DEPS := $(SRC) $(HTML) bookshops.asd # and some more...

# list of supported locales
LOCALES := fr_fr
# Example of how the variable should look after adding a new locale:
# LOCALES := fr_FR en_GB

.PHONY: tr
tr: ${MO_FILES}

PO_TEMPLATE_DIR := locale/templates/LC_MESSAGES
PO_TEMPLATE := ${PO_TEMPLATE_DIR}/bookshops.pot

# Rule to extract translatable strings from SRC
${PO_TEMPLATE_DIR}/lisp.pot: $(SRC)
	mkdir -p $(@D)
	xgettext -k_ -kN_ --language=lisp -o $@ $^

# and then, come the rules to extract strings from HTML templates
# and build everything.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;extracting-strings-from-html-templates&#34;&gt;Extracting strings from HTML templates&lt;/h2&gt;

&lt;p&gt;Now, we need to fire a Lisp and call the Djula function that knows how to collect marked strings.&lt;/p&gt;

&lt;p&gt;The Djula doc shows how to do it with &lt;code&gt;djula:xgettext-templates&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sbcl --eval &#39;(ql:quickload :my-project)&#39;
     --eval &#39;(djula::xgettext-templates
               :my-project-package
               (asdf:system-relative-pathname :my-project &amp;quot;i18n/xgettext.lisp&amp;quot;))&#39;
     --quit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This function receives 2 arguments: your project package and the
output file, where to store results. It stores them in a .lisp file in
a regular gettext syntax, so this .lisp file is then read by a regular
xgettext command (looking for &lt;code&gt;_&lt;/code&gt; strings), and this command
ultimately creates the .pot file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;find src -iname &amp;quot;*.lisp&amp;quot; | xargs xgettext --from-code=UTF-8 --keyword=_ --output=i18n/my-project.pot --sort-output
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We did it a bit differently with two other functions, in order to keep track of the source filename of each string (&lt;a href=&#34;https://gitlab.com/myopenbookstore/openbookstore/-/blob/master/src/i18n.lisp&#34;&gt;our source here&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#|
This could technically be just
(mapcan #&#39;djula.locale:file-template-translate-strings
        (djula:list-asdf-system-templates &amp;quot;bookshops&amp;quot; &amp;quot;src/web/templates&amp;quot;))

But I (fstamour) made it just a bit more complex in order to keep track of the source (just the
filename) of each translatable strings. Hence why the hash-table returned is named `locations`.
|#
(defun extract-translate-strings ()
  &amp;quot;Extract all {_ ... _} string from the djula templates.&amp;quot;
  (loop
    :with locations = (make-hash-table :test &#39;equal)
    :for path :in (djula:list-asdf-system-templates &amp;quot;bookshops&amp;quot; &amp;quot;src/web/templates&amp;quot;)
    :for strings = (djula.locale:file-template-translate-strings path)
    :do (loop :for string :in strings
              :unless (gethash string locations)
                :do (setf (gethash string locations) path))
    :finally (return locations)))


(defun update-djula.pot ()
  &amp;quot;Update djula.pot from *.html files.&amp;quot;
  (with-open-file (s (asdf:system-relative-pathname &amp;quot;bookshops&amp;quot; &amp;quot;locale/templates/LC_MESSAGES/djula.pot&amp;quot;)
                     :direction :output
                     :if-exists :supersede
                     :if-does-not-exist :create)
    (let* ((locations (extract-translate-strings))
           (strings (alexandria:hash-table-keys locations)))
      (loop
        :for string :in strings
        :for location = (gethash string locations)
        :do
           (format s &amp;quot;~%#: ~a~%#, lisp-format~%msgid ~s~%msgstr \&amp;quot;\&amp;quot; ~%&amp;quot;
                   (enough-namestring location (asdf:system-relative-pathname &amp;quot;bookshops&amp;quot; &amp;quot;&amp;quot;))
                   string)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So this is our Makefile:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-Makefile&#34;&gt;# Rule to extract translatable strings from djula templates
${PO_TEMPLATE_DIR}/djula.pot: $(HTML) src/i18n.lisp
	$(LISP) --non-interactive \
		--eval &#39;(ql:quickload &amp;quot;deploy&amp;quot;)&#39; \
		--eval &#39;(ql:quickload &amp;quot;cl+ssl&amp;quot;)&#39; \
		--eval &#39;(asdf:load-asd (truename &amp;quot;bookshops.asd&amp;quot;))&#39; \
		--eval &#39;(push :djula-binary *features*)&#39; \
		--eval &#39;(ql:quickload :bookshops)&#39; \
		--eval &#39;(bookshops.i18n:update-djula.pot)&#39;

# Rule to combine djula.pot and lisp.pot into bookshops.pot
${PO_TEMPLATE}: ${PO_TEMPLATE_DIR}/djula.pot ${PO_TEMPLATE_DIR}/lisp.pot
	msgcat --use-first $^ &amp;gt; $@

# Rule to generate or update the .po files from the .pot file
locale/%/LC_MESSAGES/bookshops.po: ${PO_TEMPLATE}
	mkdir -p $(@D)
	[ -f $@ ] || msginit --locale=$* \
          -i $&amp;lt; \
          -o $@ \
	&amp;amp;&amp;amp; msgmerge --update $@ $&amp;lt;

# Rule to create the .mo files from the .po files
locale/%/LC_MESSAGES/bookshops.mo: locale/%/LC_MESSAGES/bookshops.po
	mkdir -p $(@D)
	msgfmt -o $@ $&amp;lt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ultimately, this is the one make target we, as a developer, have to use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-Makefile&#34;&gt;.PHONY: tr
tr: ${MO_FILES}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;loading-the-translations&#34;&gt;Loading the translations&lt;/h2&gt;

&lt;p&gt;Once gettext is run and we added a couple translations, we have to load them inside our lisp app. We use &lt;code&gt;gettext:preload-catalogs&lt;/code&gt;, as in:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Only preload the translations into the image if we&#39;re not deployed yet.
(unless (deploy:deployed-p)
  (format *debug-io* &amp;quot;~%Reading all *.mo files...&amp;quot;)
  (gettext:preload-catalogs
   ;; Tell gettext where to find the .mo files
   #.(asdf:system-relative-pathname :bookshops &amp;quot;locale/&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a top-level instruction, we want it to work on our machine
during development or when building the binary (situations where asdf
will find the required directories), but not when we &lt;em&gt;run&lt;/em&gt; the binary
(the location wanted by asdf would not exist on another machine), and
we can do this with the help of
&lt;a href=&#34;https://github.com/Shinmera/deploy&#34;&gt;Deploy&lt;/a&gt;
(&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html#with-deploy---ship-foreign-libraries-dependencies&#34;&gt;Cookbook&lt;/a&gt; recipe).&lt;/p&gt;

&lt;p&gt;The gettext hash-table is saved into the binary, we correctly find our
translations when we deploy it.&lt;/p&gt;

&lt;h2 id=&#34;during-development&#34;&gt;During development&lt;/h2&gt;

&lt;p&gt;Set the current locale:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun set-locale (locale)
  &amp;quot;Setf gettext:*current-locale* and djula:*current-language* if LOCALE seems valid.&amp;quot;
  ;; It is valid to set the locale to nil.
  (when (and locale
             (not (member locale (list-loaded-locales)
                          :test &#39;string=)))
    (error &amp;quot;Locale not valid or not available: ~s&amp;quot; locale))
  (setf *current-locale* locale
        djula:*current-language* locale))


(defmacro with-locale ((locale) &amp;amp;body body)
  &amp;quot;Calls BODY with gettext:*current-locale* and djula:*current-language* set to LOCALE.&amp;quot;
  `(let (*current-locale*
         djula:*current-language*)
     (set-locale ,locale)
     ,@body))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;BOOKSHOPS&amp;gt; (djula:set-locale &amp;quot;fr_fr&amp;quot;)   ;; &amp;lt;-- same as the ones declared in the Makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The change takes effect immediately.&lt;/p&gt;

&lt;p&gt;However, run this when developping to reload the translations into gettext&amp;rsquo;s catalogue:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+ (or)
(progn
  ;; Clear gettext&#39;s cache (it&#39;s a hash table)
  (clrhash gettext::*catalog-cache*)
  (gettext:preload-catalogs
   ;; Tell gettext where to find the .mo files
   #.(asdf:system-relative-pathname :bookshops &amp;quot;locale/&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;rsquo;ll add a file watcher to automatically reload them later, when I work more with the system.&lt;/p&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Run this to see the list of loaded message for a specific locale
#+ (or)
(gettext::catalog-messages
 (gethash &#39;(&amp;quot;fr_fr&amp;quot; :LC_MESSAGES &amp;quot;bookshops&amp;quot;)  ;; yes, a list for the HT key.
	  gettext::*catalog-cache*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;; Test the translation of a string
#+ (or)
(with-locale (&amp;quot;fr_fr&amp;quot;)
  (_ &amp;quot;Please login to continue&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;

&lt;p&gt;From our readme:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;make tr&lt;/code&gt; takes care of extracting the strings (generating &lt;code&gt;.pot&lt;/code&gt;
files) and generating or updating (with &lt;code&gt;msgmerge&lt;/code&gt;) &lt;code&gt;.po&lt;/code&gt; and &lt;code&gt;.mo&lt;/code&gt;
files for each locale. The &lt;code&gt;.mo&lt;/code&gt; files are loaded in the lisp image at
compile-time (or run-time, when developing the application).&lt;/p&gt;

&lt;h3 id=&#34;how-to-add-a-new-locale&#34;&gt;How to add a new locale?&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add the new locale to the &lt;code&gt;LOCALES&lt;/code&gt; variable in the makefile.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;make tr&lt;/code&gt;. This will generate the &lt;code&gt;.po&lt;/code&gt; file (and directory)
for the new locale.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;how-to-add-a-translation-for-an-existing-string&#34;&gt;How to add a translation for an existing string?&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Update the &lt;code&gt;.po&lt;/code&gt; file for the locale.

&lt;ol&gt;
&lt;li&gt;Find the &lt;code&gt;msgid&lt;/code&gt; that corresponds to the string you want to
translate.&lt;/li&gt;
&lt;li&gt;Fill the &lt;code&gt;msgstr&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;make tr&lt;/code&gt; to update the &lt;code&gt;.mo&lt;/code&gt; file for the locale.&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;Another blog post I wish I had read a couple years ago o/&lt;/p&gt;

&lt;p&gt;You are welcome to make everything even easier to use.&lt;/p&gt;

&lt;p&gt;Happy lisping!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to parse command line arguments in Common Lisp (bis)</title>
      <link>/blog/how-to-parse-command-line-arguments-in-common-lisp/</link>
      <pubDate>Wed, 19 Apr 2023 11:44:56 +0200</pubDate>
      
      <guid>/blog/how-to-parse-command-line-arguments-in-common-lisp/</guid>
      <description>

&lt;p&gt;In 2018, I wrote a blog post and the Cookbook page on how to build Common Lisp binaries, and how to parse command-line arguments with the unix-opts library.&lt;/p&gt;

&lt;p&gt;But since then, new libraries were created an they are pretty good! They are simpler to use, and have much more features. I had a good experience with Clingon: its usage is clear, its documentation is very good, it is very flexible (it has hooks and generic functions waiting to have an &lt;code&gt;:around&lt;/code&gt; method) and &lt;a href=&#34;https://github.com/dnaeon/&#34;&gt;@dnaeon&lt;/a&gt; is not at his first great CL project.&lt;/p&gt;

&lt;p&gt;You might give &lt;a href=&#34;https://github.com/sjl/adopt/&#34;&gt;adopt&lt;/a&gt; a look, or maybe &lt;a href=&#34;https://github.com/40ants/defmain&#34;&gt;defmain&lt;/a&gt; though I felt a little something was missing.&lt;/p&gt;

&lt;p&gt;So I updated the guide to use Clingon. Let&amp;rsquo;s go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;=&amp;gt; This article is &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html&#34;&gt;best read on the Common Lisp Cookbook&lt;/a&gt; where it will receive updates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a reminder to this often-asked question, my SBCL standalone
binaries, with dozens of dependencies (SBCL&amp;rsquo;s compiler and debugger
(very useful to load code during the application&amp;rsquo;s lifecycle), a web
server, static assets and other libraries) weight about 30MB and start
in ±0.4s, with SBCL compression. Without compression, it&amp;rsquo;s more about
130MB and 0.01s.&lt;/p&gt;

&lt;h2 id=&#34;parsing-command-line-arguments&#34;&gt;Parsing command line arguments&lt;/h2&gt;

&lt;p&gt;SBCL stores the command line arguments into &lt;code&gt;sb-ext:*posix-argv*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But that variable name differs from implementations, so we want a
way to handle the differences for us.&lt;/p&gt;

&lt;p&gt;We have &lt;code&gt;(uiop:command-line-arguments)&lt;/code&gt;, shipped in ASDF and included in
nearly all implementations.
From anywhere in your code, you can simply check if a given string is present in this list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(member &amp;quot;-h&amp;quot; (uiop:command-line-arguments) :test #&#39;string-equal)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s good, but we also want to parse the arguments, have facilities to check short and long options, build a help message automatically, etc.&lt;/p&gt;

&lt;p&gt;We chose the &lt;a href=&#34;https://github.com/dnaeon/clingon&#34;&gt;Clingon&lt;/a&gt; library,
because it may have the richest feature set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it handles subcommands,&lt;/li&gt;
&lt;li&gt;it supports various kinds of options (flags, integers, booleans, counters, enums…),&lt;/li&gt;
&lt;li&gt;it generates Bash and Zsh completion files as well as man pages,&lt;/li&gt;
&lt;li&gt;it is extensible in many ways,&lt;/li&gt;
&lt;li&gt;we can easily try it out on the REPL&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&amp;rsquo;s download it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload &amp;quot;clingon&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As often, work happens in two phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we first declare the options that our application accepts, their
kind (flag, string, integer…), their long and short names and the
required ones.&lt;/li&gt;
&lt;li&gt;we ask Clingon to parse the command-line options and run our app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;declaring-options&#34;&gt;Declaring options&lt;/h3&gt;

&lt;p&gt;We want to represent a command-line tool with this possible usage:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ myscript [-h, --help] [-n, --name NAME]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ultimately, we need to create a Clingon command (with
&lt;code&gt;clingon:make-command&lt;/code&gt;) to represent our application. A command is
composed of options and of a handler function, to do the logic.&lt;/p&gt;

&lt;p&gt;So first, let&amp;rsquo;s create options. Clingon already handles &amp;ldquo;&amp;ndash;help&amp;rdquo; for us, but not the short version. Here&amp;rsquo;s how we use &lt;code&gt;clingon:make-option&lt;/code&gt; to create an option:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(clingon:make-option
 :flag                ;; &amp;lt;--- option kind. A &amp;quot;flag&amp;quot; does not expect a parameter on the CLI.
 :description &amp;quot;short help&amp;quot;
 ;; :long-name &amp;quot;help&amp;quot; ;; &amp;lt;--- long name, sans the &amp;quot;--&amp;quot; prefix, but here it&#39;s a duplicate.
 :short-name #\h      ;; &amp;lt;--- short name, a character
 ;; :required t       ;; &amp;lt;--- is this option always required? In our case, no.
 :key :help)          ;; &amp;lt;--- the internal reference to use with getopt, see later.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a &lt;strong&gt;flag&lt;/strong&gt;: if &amp;ldquo;-h&amp;rdquo; is present on the command-line, the
option&amp;rsquo;s value will be truthy, otherwise it will be falsy. A flag does
not expect an argument, it&amp;rsquo;s here for itself.&lt;/p&gt;

&lt;p&gt;Similar kind of options would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:boolean&lt;/code&gt;: that one expects an argument, which can be &amp;ldquo;true&amp;rdquo; or 1 to be truthy. Anything else is considered falsy.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:counter&lt;/code&gt;: a counter option counts how many times the option is provided on the command line. Typically, use it with &lt;code&gt;-v&lt;/code&gt; / &lt;code&gt;--verbose&lt;/code&gt;, so the user could use &lt;code&gt;-vvv&lt;/code&gt; to have extra verbosity. In that case, the option value would be 3. When this option is not provided on the command line, Clingon sets its value to 0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;rsquo;ll create a second option (&amp;ldquo;&amp;ndash;name&amp;rdquo; or &amp;ldquo;-n&amp;rdquo; with a parameter) and we put everything in a litle function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; The naming with a &amp;quot;/&amp;quot; is just our convention.
(defun cli/options ()
  &amp;quot;Returns a list of options for our main command&amp;quot;
  (list
   (clingon:make-option
    :flag
    :description &amp;quot;short help.&amp;quot;
    :short-name #\h
    :key :help)
   (clingon:make-option
    :string              ;; &amp;lt;--- string type: expects one parameter on the CLI.
    :description &amp;quot;Name to greet&amp;quot;
    :short-name #\n
    :long-name &amp;quot;name&amp;quot;
    :env-vars &#39;(&amp;quot;USER&amp;quot;)     ;; &amp;lt;-- takes this default value if the env var exists.
    :initial-value &amp;quot;lisper&amp;quot; ;; &amp;lt;-- default value if nothing else is set.
    :key :name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second option we created is of kind &lt;code&gt;:string&lt;/code&gt;. This option expects one argument, which will be parsed as a string. There is also &lt;code&gt;:integer&lt;/code&gt;, to parse the argument as an integer.&lt;/p&gt;

&lt;p&gt;There are more option kinds of Clingon, which you will find on its good documentation: &lt;code&gt;:choice&lt;/code&gt;, &lt;code&gt;:enum&lt;/code&gt;, &lt;code&gt;:list&lt;/code&gt;, &lt;code&gt;:filepath&lt;/code&gt;, &lt;code&gt;:switch&lt;/code&gt; and so on.&lt;/p&gt;

&lt;h3 id=&#34;top-level-command&#34;&gt;Top-level command&lt;/h3&gt;

&lt;p&gt;We have to tell Clingon about our top-level command.
&lt;code&gt;clingon:make-command&lt;/code&gt; accepts some descriptive fields, and two important ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:options&lt;/code&gt; is a list of Clingon options, each created with &lt;code&gt;clingon:make-option&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:handler&lt;/code&gt; is the function that will do the app&amp;rsquo;s logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And finally, we&amp;rsquo;ll use &lt;code&gt;clingon:run&lt;/code&gt; in our main function (the entry
point of our binary) to parse the command-line arguments, and apply
our command&amp;rsquo;s logic. During development, we can also manually call
&lt;code&gt;clingon:parse-command-line&lt;/code&gt; to try things out.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a minimal command. We&amp;rsquo;ll define our handler function afterwards:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun cli/command ()
  &amp;quot;A command to say hello to someone&amp;quot;
  (clingon:make-command
   :name &amp;quot;hello&amp;quot;
   :description &amp;quot;say hello&amp;quot;
   :version &amp;quot;0.1.0&amp;quot;
   :authors &#39;(&amp;quot;John Doe &amp;lt;john.doe@example.org&amp;quot;)
   :license &amp;quot;BSD 2-Clause&amp;quot;
   :options (cli/options) ;; &amp;lt;-- our options
   :handler #&#39;null))  ;; &amp;lt;--  to change. See below.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, we can already test things out on the REPL.&lt;/p&gt;

&lt;h3 id=&#34;testing-options-parsing-on-the-repl&#34;&gt;Testing options parsing on the REPL&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;clingon:parse-command-line&lt;/code&gt;: it wants a top-level command, and a list of command-line arguments (strings):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (clingon:parse-command-line (cli/command) &#39;(&amp;quot;-h&amp;quot; &amp;quot;-n&amp;quot; &amp;quot;me&amp;quot;))
#&amp;lt;CLINGON.COMMAND:COMMAND name=hello options=5 sub-commands=0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;p&gt;We can even &lt;code&gt;inspect&lt;/code&gt; this command object, we would see its properties (name, hooks, description, context…), its list of options, etc.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s try again with an unknown option:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (clingon:parse-command-line (cli/command) &#39;(&amp;quot;-x&amp;quot;))
;; =&amp;gt; debugger: Unknown option -x of kind SHORT
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In that case, we are dropped into the interactive debugger, which says&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Unknown option -x of kind SHORT
   [Condition of type CLINGON.CONDITIONS:UNKNOWN-OPTION]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we are provided a few restarts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Restarts:
 0: [DISCARD-OPTION] Discard the unknown option
 1: [TREAT-AS-ARGUMENT] Treat the unknown option as a free argument
 2: [SUPPLY-NEW-VALUE] Supply a new value to be parsed
 3: [RETRY] Retry SLIME REPL evaluation request.
 4: [*ABORT] Return to SLIME&#39;s top level.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which are very practical. If we needed, we could create an &lt;code&gt;:around&lt;/code&gt;
method for &lt;code&gt;parse-command-line&lt;/code&gt;, handle Clingon&amp;rsquo;s conditions with
&lt;code&gt;handler-bind&lt;/code&gt; and use its restarts, to do something different with
unknown options. But we don&amp;rsquo;t need that yet, if ever: we want our
command-line parsing engine to warn us on invalid options.&lt;/p&gt;

&lt;p&gt;Last but not least, we can see how Clingon prints our CLI tool&amp;rsquo;s usage information:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CL-USER&amp;gt; (clingon:print-usage (cli/command) t)
NAME:
  hello - say hello

USAGE:
  hello [options] [arguments ...]

OPTIONS:
      --help          display usage information and exit
      --version       display version and exit
  -h                  short help.
  -n, --name &amp;lt;VALUE&amp;gt;  Name to greet [default: lisper] [env: $USER]

AUTHORS:
  John Doe &amp;lt;john.doe@example.org

LICENSE:
  BSD 2-Clause
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can tweak the &amp;ldquo;USAGE&amp;rdquo; part with the &lt;code&gt;:usage&lt;/code&gt; key parameter of the lop-level command.&lt;/p&gt;

&lt;h3 id=&#34;handling-options&#34;&gt;Handling options&lt;/h3&gt;

&lt;p&gt;When the parsing of command-line arguments succeeds, we need to do something with them. We introduce two new Clingon functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;clingon:getopt&lt;/code&gt; is used to get an option&amp;rsquo;s value by its &lt;code&gt;:key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clingon:command-arguments&lt;/code&gt; gets use the free arguments remaining on the command-line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;rsquo;s how to use them:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (let ((command (clingon:parse-command-line (cli/command) &#39;(&amp;quot;-n&amp;quot; &amp;quot;you&amp;quot; &amp;quot;last&amp;quot;))))
           (format t &amp;quot;name is: ~a~&amp;amp;&amp;quot; (clingon:getopt command :name))
           (format t &amp;quot;free args are: ~s~&amp;amp;&amp;quot; (clingon:command-arguments command)))
name is: you
free args are: (&amp;quot;last&amp;quot;)
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is with them that we will write the handler of our top-level command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun cli/handler (cmd)
  &amp;quot;The handler function of our top-level command&amp;quot;
  (let ((free-args (clingon:command-arguments cmd))
        (name (clingon:getopt cmd :name)))  ;; &amp;lt;-- using the option&#39;s :key
    (format t &amp;quot;Hello, ~a!~%&amp;quot; name)
    (format t &amp;quot;You have provided ~a more free arguments~%&amp;quot; (length free-args))
    (format t &amp;quot;Bye!~%&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We must tell our top-level command to use this handler:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; from above:
(defun cli/command ()
  &amp;quot;A command to say hello to someone&amp;quot;
  (clingon:make-command
   ...
   :handler #&#39;cli/handler))  ;; &amp;lt;-- changed.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We now only have to write the main entry point of our binary and we&amp;rsquo;re done.&lt;/p&gt;

&lt;p&gt;By the way, &lt;code&gt;clingon:getopt&lt;/code&gt; returns 3 values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the option&amp;rsquo;s value&lt;/li&gt;
&lt;li&gt;a boolean, indicating wether this option was provided on the command-line&lt;/li&gt;
&lt;li&gt;the command which provided the option for this value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See also &lt;code&gt;clingon:opt-is-set-p&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;main-entry-point&#34;&gt;Main entry point&lt;/h3&gt;

&lt;p&gt;This can be any function, but to use Clingon, use its &lt;code&gt;run&lt;/code&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun main ()
  &amp;quot;The main entrypoint of our CLI program&amp;quot;
  (clingon:run (cli/command)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To use this main function as your binary entry point, see above how to build a Common Lisp binary. A reminder: set it in your .asd system declaration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;:entry-point &amp;quot;my-package::main&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;rsquo;s about it. Congratulations, you can now properly parse command-line arguments!&lt;/p&gt;

&lt;p&gt;Go check Clingon&amp;rsquo;s documentation, because there is much more to it: sub-commands, contexts, hooks, handling a C-c (see also the Cookbook for that), developing new options such as an email kind, Bash and Zsh completion…&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Thanks for reading and thanks again to @dnaeon.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>These Years in Common Lisp: 2022 in review</title>
      <link>/blog/these-years-in-common-lisp-2022-in-review/</link>
      <pubDate>Mon, 09 Jan 2023 19:54:29 +0100</pubDate>
      
      <guid>/blog/these-years-in-common-lisp-2022-in-review/</guid>
      <description>

&lt;p&gt;And 2022 is over. The Common Lisp language and environment are solid
and stable, yet evolve. Implementations, go-to libraries, best
practices, communities evolve. We don&amp;rsquo;t need a &amp;ldquo;State of the
Ecosystem&amp;rdquo; every two weeks but still, what happened and what did you
miss in 2022?&lt;/p&gt;

&lt;p&gt;This is my pick of the most exciting, fascinating, interesting or just
cool projects, tools, libraries and articles that popped-up during
that time (with a few exceptions that appeared in late 2021).&lt;/p&gt;

&lt;p&gt;This overview is not a &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/state-of-the-common-lisp-ecosystem-2020/&#34;&gt;&amp;ldquo;State of the CL ecosystem&amp;rdquo;&lt;/a&gt; (&lt;a href=&#34;https://news.ycombinator.com/item?id=26065511&#34;&gt;HN comments (133)&lt;/a&gt;) that I did in
2020, for which you can find complementary comments on HN.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think this article (of sorts) is definitely helpful for onlookers to Common Lisp, but doesn&amp;rsquo;t provide the full &amp;ldquo;story&amp;rdquo; or &amp;ldquo;feel&amp;rdquo; of Common Lisp, and I want to offer to HN my own perspective.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And, suffice to say, I tried to talk about the most important things,
but this article (of sorts) is by no means a compilation of &lt;em&gt;all&lt;/em&gt; new
CL projects or all the articles published on the internet. Look on
Reddit, Quicklisp releases, Github, and my favourite resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome-cl&lt;/a&gt; - a curated list of libraries (there might be more than you think)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;the CL Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I had to pick 3 achievements they would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SBCL developments: &lt;strong&gt;SBCL is now callable as a shared library&lt;/strong&gt;. See below in &amp;ldquo;Implementations&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a new 3D graphics project: Kons-9&lt;/strong&gt;: &amp;ldquo;The idea would be to develop a system along the lines of Blender/Maya/Houdini, but oriented towards the strengths of Common Lisp&amp;rdquo;. And the project progresses at a good pace.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLOG, the Common Lisp Omnificent GUI&lt;/strong&gt;. It&amp;rsquo;s like a GUI framework
to create web apps. Based on websockets, it offers a light
abstraction to create fully-dynamic web applications, in Common
Lisp. It has lots of demos to create websites, web apps, games, and
it ships a complete editor. For development, we can connect our Lisp
REPL to the browser, and see changes on the fly. The author had a
similar commercial product written in Ada, discovered Common Lisp,
and is now super active on this project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&amp;rsquo;s go for more.&lt;/p&gt;

&lt;p&gt;Thanks to @k1d77a, @Hexstream, @digikar and @stylewarning for their feedback.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#documentation&#34;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#implementations&#34;&gt;Implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#jobs&#34;&gt;Jobs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#projects&#34;&gt;Projects&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#language-libraries&#34;&gt;Language libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#editors-online-editors-repls-plugins&#34;&gt;Editors, online editors, REPLs, plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#concurrency&#34;&gt;Concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#databases&#34;&gt;Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#delivery-tools&#34;&gt;Delivery tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#games&#34;&gt;Games&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#graphics-guis&#34;&gt;Graphics, GUIs&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#kons-9-a-new-3d-graphics-project&#34;&gt;Kons-9, a new 3D graphics project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#interfaces-with-other-languages&#34;&gt;Interfaces with other languages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#numerical-and-scientific&#34;&gt;Numerical and scientific&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#web&#34;&gt;Web&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#clog&#34;&gt;CLOG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#new-releases&#34;&gt;New releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#re-discoveries&#34;&gt;(re) discoveries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#articles&#34;&gt;Articles&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#graphics&#34;&gt;Graphics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tooling&#34;&gt;Tooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#around-the-language&#34;&gt;Around the language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#web-related&#34;&gt;Web related&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-articles&#34;&gt;Other articles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#screencasts-and-podcasts&#34;&gt;Screencasts and podcasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-discussions&#34;&gt;Other discussions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#community&#34;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#learning-lisp&#34;&gt;Learning Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#common-lisp-vs-&#34;&gt;Common Lisp VS …&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;p&gt;A newcomer to Lisp came, asked a question, and suddenly he created a super useful rendering of the specification. Check it out!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://cl-community-spec.github.io/pages/index.html&#34;&gt;Common Lisp CommunitySpec (CLCS)&lt;/a&gt; -  a rendition of the Common Lisp ANSI Specification draft.

&lt;ul&gt;
&lt;li&gt;Github: &lt;a href=&#34;https://github.com/fonol/cl-community-spec&#34;&gt;https://github.com/fonol/cl-community-spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It is readable, it has syntax highlighting for code snippets, an interactive search bar, it looks modern, it is open.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that&amp;rsquo;s not all, he also started work on a new Common Lisp editor, built in Rust and Tauri, see below.&lt;/p&gt;

&lt;p&gt;We continue to enrich the Common Lisp Cookbook. You are welcome to join, since documention is best built by newcomers for newcomers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/releases/tag/2022-09-14&#34;&gt;New CL Cookbook EPUB and PDF release - mainly readability and file format improvements - thanks to the 13 contributors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A resurrected project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://llthw.common-lisp.dev/&#34;&gt;Learn Lisp the Hard Way is back online&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cdr.common-lisp.dev/&#34;&gt;the revamped Common Lisp Document Repository (CDR) site&lt;/a&gt;, &amp;ldquo;a repository of documents that are of interest to the Common Lisp community. The most important property of a CDR document is that it will never change&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/s9r57l/via_marco_antoniottis_blog_the_revamped_common/&#34;&gt;comments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/i-am-creating-a-common-lisp-video-course-on-udemy/&#34;&gt;I am creating a Common Lisp video course on Udemy 🎥&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;read more about my motivation and follow the project on Github: &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;https://github.com/vindarel/common-lisp-course-in-videos/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the course has some free videos. If you are a student, drop me a line for a free link.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;direct link to the course&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Thanks for your support!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;implementations&#34;&gt;Implementations&lt;/h1&gt;

&lt;p&gt;We saw achievements in at least &lt;del&gt;7&lt;/del&gt; 8 implementations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.sbcl.org/all-news.html&#34;&gt;SBCL continues to ship monthly&lt;/a&gt;. In 2022:

&lt;ul&gt;
&lt;li&gt;🚀 SBCL is now &lt;strong&gt;callable as a shared library&lt;/strong&gt;. See sbcl-librarian below.&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://www.sbcl.org/manual/index.html#sb_002dsimd&#34;&gt;sb-simd&lt;/a&gt; - &lt;strong&gt;SIMD&lt;/strong&gt; programming in SBCL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;core compression&lt;/strong&gt; uses zstd instead of zip: compression is about 4 times faster, decompression about two times, compression saves ±10% of size.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trace&lt;/code&gt; now supports tracing macro functions, compiler-macro functions, individual methods and local functions (flet and labels) (SBCL 2.2.5)&lt;/li&gt;
&lt;li&gt;the SBCL repository reached 20,000 commits.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bohonghuang/sbcl-termux-build&#34;&gt;Prebuilt SBCL binary for Android (Termux)&lt;/a&gt; (unofficial)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/clasp-developers/clasp/releases/tag/2.0.0&#34;&gt;Clasp 2.0.0 released&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;This is Common Lisp on LLVM.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=tQgkvghzW0M&#34;&gt;Christian Schafmeister talk - brief update about his &amp;ldquo;molecular lego&amp;rdquo; supported by his Lisp compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s less funding than in the 80s, but still funding: &amp;ldquo;CLASP was supported by The Defense Threat Reduction Agency, The National Institutes of Health, The National Science Foundation&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;ECL:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/sqrdio/lqml_a_lightweight_ecl_binding_to_qml_both_qt5/&#34;&gt;LQML: a lightweight ECL binding to QML (both Qt5 and Qt6) derived from EQL5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tested on the following platforms: Linux, macOS, android, iOS.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/ys7jpl/ecl_targetting_wasm_via_emscripten_preliminary/&#34;&gt;ECL targetting WASM via Emscripten - preliminary support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/news/news41.html&#34;&gt;LispWorks Personal Edition updated to version 8.0.1&lt;/a&gt;, incl. &lt;em&gt;native Apple Silicon version&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/downloads/patch-selection.html#lw80monterey&#34;&gt; additional important LispWorks 8 patch for macOS 12.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/tb5ehb/major_new_release_of_allegro_common_lisp_express/&#34;&gt;Major New release of Allegro Common Lisp Express Edition for 10.1&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Browser-based IDE for Linux and macOS&lt;/li&gt;
&lt;li&gt;no syntax highlighting for the editor though :S&lt;/li&gt;
&lt;li&gt;Applications built using Common Graphics can use browsers for delivery. Firefox, Chrome, Safari, Edge and many other browsers are supported.&lt;/li&gt;
&lt;li&gt;New platforms: aarch64, x86_64&lt;/li&gt;
&lt;li&gt;download: &lt;a href=&#34;https://franz.com/downloads/clp/survey&#34;&gt;https://franz.com/downloads/clp/survey&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://abcl.org/release-notes-1.9.0.shtml&#34;&gt;ABCL 1.9.0&lt;/a&gt; was released in May.

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;ABCL 1.9.0 has been best tested on the openjdk8, openjdk11, and openjdk17 runtimes. It will run other places but those are the best supported.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zqy697/gnu_common_lisp_2613_is_released/&#34;&gt;GNU Common Lisp 2.6.13 released&lt;/a&gt;, after 8 years.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New implementation! It&amp;rsquo;s 2022 and people start new CL implementations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nptcl/npt&#34;&gt;NPT&lt;/a&gt; - an implementation of ANSI Common Lisp in C.

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/uiewwn/npt_an_implementation_of_ansi_common_lisp_in_c/&#34;&gt;comments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/gsou/LCL&#34;&gt;LCL, Lua Common Lisp&lt;/a&gt; - The goal of this project is to provide an implementation of Common Lisp that can be used wherever an unmodified Lua VM is running.

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;not&lt;/em&gt; a complete implementation.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are doing great work to revive a Lisp machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://interlisp.org/news/2022medleyannualreport/&#34;&gt;2022 Medley Interlisp Annual Report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Medley Interlisp is a project aiming to restore the Interlisp-D software environment of the Lisp Machines Xerox produced since the early 1980s, and rehost it on modern operating systems and computers. It&amp;rsquo;s unique in the retrocomputing space in that many of the original designers and implementors of major parts of the system are participating in the effort.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Paolo Amoroso &lt;a href=&#34;https://journal.paoloamoroso.com/my-encounter-with-medley-interlisp&#34;&gt;blog post: my encounter with Medley Interlisp&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;jobs&#34;&gt;Jobs&lt;/h1&gt;

&lt;p&gt;I won&amp;rsquo;t list expired job announces, but this year Lispers could apply for jobs in: web development(&lt;a href=&#34;https://webcheckout.net/&#34;&gt;WebCheckout&lt;/a&gt;, freelance announces), cloud service providers (&lt;a href=&#34;https://www.keepit.com/&#34;&gt;Keepit&lt;/a&gt;), big-data analysis (&lt;a href=&#34;https://www.ravenpack.com/&#34;&gt;Ravenpack&lt;/a&gt;, and chances are they are still hiring)), quantum computing (&lt;a href=&#34;https://www.hrl.com/&#34;&gt;HLR Laboratories&lt;/a&gt;), AI (&lt;a href=&#34;https://mind.ai/&#34;&gt;Mind AI&lt;/a&gt;, &lt;a href=&#34;https://www.sri.com/&#34;&gt;SRI International&lt;/a&gt;), real-time data aggregration and alerting engines for energy systems (&lt;a href=&#34;https://3e.eu/&#34;&gt;3E&lt;/a&gt;); for a startup building autism tech (and using CLOG already); there have been a job seeking to rewrite a Python backend to Common Lisp (&lt;a href=&#34;https://www.riffitnow.com/&#34;&gt;RIFFIT&lt;/a&gt;); there have been some bounties; etc.&lt;/p&gt;

&lt;p&gt;Prior Lisp experience was not 100% necessary. There were openings for junior and senior levels, remote and not remote (Australia for &amp;ldquo;a big corp&amp;rdquo;, U.S., Spain, Ukraine…).&lt;/p&gt;

&lt;p&gt;Comes a question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/vvszte/any_ideas_for_strategies_to_find_jobs_with_lisp/&#34;&gt;Any Ideas for strategies to find jobs with lisp?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I remind the reader that most Lisp jobs do &lt;em&gt;not&lt;/em&gt; have a public job posting, instead candidates are often found organically on the community channels: IRC, Twitter, Discord, Reddit… or teams simply train their new developer.&lt;/p&gt;

&lt;p&gt;In 2022 we added a few companies to the ongoing, non-official list on &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;awesome-lisp-companies&lt;/a&gt;. If your company uses Common Lisp, feel free to tell us on an issue or in the comments!&lt;/p&gt;

&lt;p&gt;For example, &lt;a href=&#34;https://feetr.io/&#34;&gt;Feetr.io&lt;/a&gt; &amp;ldquo;is entirely Lisp&amp;rdquo;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lisp was a conscious decision because it allows a small team to be incredibly productive, plus the fact that it&amp;rsquo;s a live image allows you to connect to it over the internet and poke and prod the current state, which has really allowed a much clearer understanding of the data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They post SLY screenshots on their Twitter^^&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://evacsound.com/&#34;&gt;Evacsound&lt;/a&gt; (&lt;a href=&#34;https://news.ycombinator.com/item?id=32178351&#34;&gt;HN&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We&amp;rsquo;re using CL in prod for an embedded system for some years now, fairly smooth sailing. It started out as an MVP/prototype so implementation was of no concern, then gained enough velocity and market interest that a rewrite was infeasible. We re-train talent on the job instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://home.pandorabots.com/&#34;&gt;Pandorabots&lt;/a&gt;, or &lt;a href=&#34;https://www.barefootnetworks.com&#34;&gt;barefootnetworks&lt;/a&gt;, designing the Intel Tofino programmable switches, and more.&lt;/p&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ultralisp.org/tags/api/&#34;&gt;Ultralisp now supports tags. We can browse a list of projects under a tag.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Ultralisp is a Quicklisp distribution that ships every five minutes.&lt;/li&gt;
&lt;li&gt;see also &lt;a href=&#34;https://www.timmons.dev/posts/clpm-040-released.html&#34;&gt;CLPM&lt;/a&gt; for a new package manager.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;language-libraries&#34;&gt;Language libraries&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/marcoheisig/Typo/&#34;&gt;Typo: A portable type inference library for Common Lisp&lt;/a&gt;, by Marco Heisig.&lt;/li&gt;
&lt;li&gt;Testing:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tdrhq/fiveam-matchers&#34;&gt;fiveam-matchers&lt;/a&gt; - An extensible, composable matchers library for FiveAM.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/z4hfl9/testiere_tddlike_dev_for_common_lisp_tests_are/&#34;&gt;testiere&lt;/a&gt; - TDD-like dev for Common Lisp. Tests are included at the top of a defun/t form. When you recompile your functions interactively, the tests are run.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/melisgl/try/&#34;&gt;melisgl/try test framework.&lt;/a&gt; - &amp;ldquo;it is what we get if we make tests functions and build a test framework on top of the condition system.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/melisgl/journal&#34;&gt;journal&lt;/a&gt; - A Common Lisp library for logging, tracing, testing and persistence&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/40ants-critic&#34;&gt;40ants-critic&lt;/a&gt; - a wrapper around LISP-CRITIC which provides a better interface to analyze ASDF systems and a command-line interface.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/x2i3lb/clede_the_common_lisp_emacs_development/&#34;&gt;CLEDE - the Common Lisp Emacs Development Environment &lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;The idea is to supply features that other language with and static analyzer have, like refactoring and code generation.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tdrhq/easy-macros&#34;&gt;easy-macros&lt;/a&gt; - An easy way to write 90% of your macros.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bigos/quicklisp-doctor&#34;&gt;Quicklisp doctor&lt;/a&gt; - a program that examines the quicklisp installation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Hectarea1996/more-cffi/&#34;&gt;more-cffi: Additional helper macros for the cffi project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;editors-online-editors-repls-plugins&#34;&gt;Editors, online editors, REPLs, plugins&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://github.com/fonol/parrot/&#34;&gt;Parrot&lt;/a&gt; -  A cross-platform Common Lisp editor.

&lt;ul&gt;
&lt;li&gt;built in &lt;strong&gt;Rust&lt;/strong&gt; with &lt;strong&gt;Tauri&lt;/strong&gt;, CodeMirror, the Slynk server.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;A hobby project started in Summer 2022. It aims to be an editor for Common Lisp (SBCL), that mostly works out of the box.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;in development, untested on Linux and Mac.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nobody-famous/alive-lsp/releases/tag/v0.1.9&#34;&gt;Alive LSP for VSCode v0.1.9 · Add initial step debugger support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://riju.codes/commonlisp&#34;&gt;Common Lisp at Riju&lt;/a&gt;, a fast online playground for every programming language.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.codewars.com/languages/commonlisp/&#34;&gt;Codewars (code training platform) now has Common Lisp (SBCL 2.0.9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zlrkcq/mobile_app_clrepl_lqml_to_replace_cl_repl_eql5/&#34;&gt;Mobile app &amp;ldquo;cl-repl&amp;rdquo; (LQML) to replace &amp;ldquo;CL REPL&amp;rdquo; (EQL5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;☆ &lt;a href=&#34;https://github.com/mmontone/slime-star&#34;&gt;slime-star&lt;/a&gt; - SLIME configuration with some extensions pre-installed.

&lt;ul&gt;
&lt;li&gt;a Lisp System Browser&lt;/li&gt;
&lt;li&gt;SLIME Doc Contribs&lt;/li&gt;
&lt;li&gt;Quicklisp Systems browsers&lt;/li&gt;
&lt;li&gt;Quicksearch utility&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmontone/slime-breakpoints&#34;&gt;Slime breakpoints&lt;/a&gt; - Inspect objects from their printed representation in output streams.&lt;/li&gt;
&lt;li&gt;custom utilities and menus.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/julian-baldwin/parachute-browser&#34;&gt;parachute-browser: A lightweight UI for using the Parachute testing framework in LispWorks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lem-project/lem/releases/tag/v1.10.0&#34;&gt;Lem editor 1.10.0: lsp-mode by default, multiple cursors, sql mode, and more.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Lem is a general purpose editor written in Common Lisp. It works for many languages thanks to its LSP client.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/fonol/parrot/main/devlog/load-file-debug-dialog.jpg&#34; style=&#34;max-width: 800px&#34;/&gt;&lt;/p&gt;

&lt;h2 id=&#34;concurrency&#34;&gt;Concurrency&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://github.com/mdbergmann/cl-gserver&#34;&gt;New version of the Sento Actor Framework released&lt;/a&gt;  with a few new goodies in future handling. Nicer syntax and futures can now be mapped.

&lt;ul&gt;
&lt;li&gt;in v2.2.0: stashing and replay of messages.&lt;/li&gt;
&lt;li&gt;in v1.12: &amp;ldquo;Shutdown and stop of actor, actor context and actor system can now wait for a full shutdown/stop of all actors to really have a clean system shutdown.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/vsbfbp/writing_distributed_apps_with_cletcd/&#34;&gt;Writing distributed apps with cl-etcd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See also &lt;a href=&#34;https://github.com/dbmcclain/Lisp-Actors/&#34;&gt;lisp-actors&lt;/a&gt;, which also does networking. It looks like more of a research project, as it doesn&amp;rsquo;t have unit-tests nor documentation, but it was used for the (stopped) Emotiq blockchain.&lt;/p&gt;

&lt;p&gt;Discussions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/x3425f/concurrency_common_lisp_vs_clojure/&#34;&gt;Concurrency: Common Lisp vs Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/tna6zo/moving_from_the_beam_to_common_lisp_what_are_my/&#34;&gt;Moving from the BEAM to Common Lisp: What are my concurrency options?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;databases&#34;&gt;Databases&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ak-coram/cl-duckdb&#34;&gt;DuckDB Lisp bindings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/yja88u/ndbapi_common_lisp_bindings_to_the_c_ndb_api_of/&#34;&gt;ndbapi: Common Lisp bindings to the C++ NDB API of RonDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/yh60n2/clsql_released_under_a_nonrestrictive_license/&#34;&gt;CLSQL released under a non-restrictive license&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zaries.wordpress.com/2022/05/31/cl-naive-store/&#34;&gt;Document Store/DB Implemented in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More choices: &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#database&#34;&gt;awesome-cl#databases&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;delivery-tools&#34;&gt;Delivery tools&lt;/h2&gt;

&lt;p&gt;There has been outstanding work done there. It is also great to see the different entities working on this. That includes SBCL developers, Doug Katzman of Google, and people at HRL Laboratories (also responsible of &lt;a href=&#34;https://coalton-lang.github.io/&#34;&gt;Coalton&lt;/a&gt;, Haskell-like on top of CL).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Have you ever wanted to call into your Lisp library from C? Have you ever written your nice scientific application in Lisp, only to be requested by people to rewrite it in Python, so they can use its functionality? Or, maybe you&amp;rsquo;ve written an RPC or pipes library to coordinate different programming languages, running things in different processes and passing messages around to simulate foreign function calls.&lt;/p&gt;

&lt;p&gt;[…]  If you prefer using SBCL, you can now join in on the cross-language programming frenzy too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;🎉 &lt;a href=&#34;https://github.com/quil-lang/sbcl-librarian&#34;&gt;sbcl-librarian&lt;/a&gt; - An opinionated interface for creating C- and Python-compatible shared libraries in Common Lisp with SBCL. Requires SBCL version &amp;gt;2.1.10.

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mstmetent.blogspot.com/2022/04/using-lisp-libraries-from-other.html&#34;&gt;introductory blogpost&lt;/a&gt;: Using Lisp libraries from other programming languages - now with SBCL.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=31054796&#34;&gt;HN comments (67)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://github.com/borodust/alien-works-delivery&#34;&gt;alien-works-delivery&lt;/a&gt; - WIP system for delivering Common Lisp applications as executable bundles. For now it only supports AppImage format for Linux and MSIX for Windows, but .APK for Android and later MacOSX and iOS bundle formats are planned too.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/qitab/bazelisp&#34;&gt;Support for compiling Common Lisp code using bazel.io&lt;/a&gt;, by the CL team at Google.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;games&#34;&gt;Games&lt;/h2&gt;

&lt;p&gt;Kandria launches on Steam on the 11th of January, in two days!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://reader.tymoon.eu/article/419&#34;&gt;2022 for Kandria in review&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kandria.com/&#34;&gt;https://kandria.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=32043026&#34;&gt;HN comments (32)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.kickstarter.com/projects/shinmera/kandria/posts/3539140&#34;&gt;They Successfully completed their Kickstarter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://courier.tymoon.eu/view/OENrrf0y2d8V7fx8WudSlUlERXpNQT09&#34;&gt;They received the Pro Helvetia grant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://reader.tymoon.eu/article/413&#34;&gt;An Overview of Kandria&amp;rsquo;s Development with Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://store.steampowered.com/app/2023440/Jettatura/&#34;&gt;Jettatura - old school RPG game released on Steam this October - built in Common Lisp (&amp;ldquo;a decade in the making&amp;rdquo;) &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/aymanosman/cl-defender&#34;&gt;cl-defender&lt;/a&gt; - Toy Game using Common Lisp and Raylib.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎥 &lt;a href=&#34;https://www.youtube.com/watch?v=usc0Znm-gbA&#34;&gt;Kandria trailer&lt;/a&gt;.&lt;/p&gt;

&lt;!-- &lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/usc0Znm-gbA&#34; title=&#34;Kandria trailer&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt; --&gt;

&lt;h2 id=&#34;graphics-guis&#34;&gt;Graphics, GUIs&lt;/h2&gt;

&lt;p&gt;We saw the release of fresh bindings for Gtk4.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://github.com/bohonghuang/cl-gtk4&#34;&gt;Writing beautiful GUI with Common Lisp and GTK4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We had bindings for Qt5… but they are still very rough, hard to install so far.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/s3xr8e/commonqt_5/&#34;&gt;CommonQt 5&lt;/a&gt; - Qt5 bindings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/xz2ibr/i_made_a_wayland_client_from_scratch_for_common/&#34;&gt;I made a Wayland client from scratch for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/JolifantoBambla/vk&#34;&gt;vk&lt;/a&gt; - CFFI bindings to Vulkan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;History:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://archive.org/details/izware_mirai_1.1sp2&#34;&gt;Izware Mirai is available on the Internet Archive&lt;/a&gt; (no source code)

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/wcyzis/hacking_lisp_on_mirai/&#34;&gt;Hacking Lisp on Mirai&lt;/a&gt; (screencast)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But an awesome novelty of 2022 is Kons-9.&lt;/p&gt;

&lt;h3 id=&#34;kons-9-a-new-3d-graphics-project&#34;&gt;Kons-9, a new 3D graphics project&lt;/h3&gt;

&lt;p&gt;🚀 A new 3D graphics project: &lt;strong&gt;Kons-9&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/weocc5/new_open_source_common_lisp_3d_graphics_project/&#34;&gt;reddit announce on August&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=32337538&#34;&gt;HN comments (80)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The idea would be to develop a system along the lines of Blender/Maya/Houdini, but oriented towards the strengths of Common Lisp.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m an old-time 3D developer who has worked in CL on and off for many years.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t consider myself an expert […] A little about me: • wrote 3D animation software used in “Jurassic Park” • software R&amp;amp;D lead on “Final Fantasy: The Spirits Within” movie • senior software developer on “The Hobbit” films.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kaveh808/kons-9&#34;&gt;kons-9, a Common Lisp 3D Graphics Project &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;🎥 &lt;a href=&#34;https://youtu.be/i0CwhEDAXB0&#34;&gt;trailer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kaveh808.medium.com/once-more-into-the-breach-a-new-common-lisp-3d-graphics-project-d401bfa083d&#34;&gt;author&amp;rsquo;s blog posts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and see also his screencasts below.&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/i0CwhEDAXB0&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;h2 id=&#34;interfaces-with-other-languages&#34;&gt;Interfaces with other languages&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/digikar99/py4cl2-cffi&#34;&gt;py4cl2-cffi&lt;/a&gt;: CFFI based alternative to py4cl2.

&lt;ul&gt;
&lt;li&gt;it does one big new thing: it supports passing CL arrays by
reference. That means we actually have access to numpy, scipy, and
friends.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;If py4cl2-cffi reaches stability, and I find that the performance
of (i) cffi-numpy, (ii) magicl, as well as (iii) a few BLAS
functions I have handcrafted for numericals turn out to be
comparable, I might no longer have to reinvent numpy.&amp;rdquo; @digikar&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/yzoslr/small_update_to_rdnzl_cl_net_bridge_by_edi_weitz/&#34;&gt;Small update to RDNZL (CL .NET bridge by Edi Weitz)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;forked project, added support for Int16, fixed Int64, re-building the supporting DLLs.&lt;/li&gt;
&lt;li&gt;see also: &lt;a href=&#34;https://github.com/Lovesan/bike/&#34;&gt;Bike&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/davidsun0/jclass&#34;&gt;jclass: Common Lisp library for Java class file manipulation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more, see awesome-cl.&lt;/p&gt;

&lt;h2 id=&#34;numerical-and-scientific&#34;&gt;Numerical and scientific&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://lisp-stat.dev/blog/releases/&#34;&gt;new Lisp Stats release&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;emphasis on plotting and polishing of sharp edges. data-frames, array operations, documentation.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=32175820&#34;&gt;HN comments (55)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;rdquo; I&amp;rsquo;ve been using lisp-stat in production as part of an algorithmic trading application I wrote. It&amp;rsquo;s been very solid, and though the plotting is (perhaps was, in light of this new release) kinda unwieldy, I really enjoyed using it. Excited to check out the newest release.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;For example, within Lisp-Stat the statistics routines [1] were written by an econometrician working for the Austrian government (Julia folks might know him - Tamas Papp). It would not be exaggerating to say his job depending on it. These are state of the art, high performance algorithms, equal to anything available in R or Python. So, if you&amp;rsquo;re doing econometrics, or something related, everything you need is already there in the tin.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;For machine learning, there&amp;rsquo;s CLML, developed by NTT. This is the largest telco in Japan, equivalent to ATT in the USA. As well, there is MGL, used to win the Higgs Boson challenge a few years back. Both actively maintained.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;For linear algebra, MagicCL was mention elsewhere in the thread. My favourite is MGL-MAT, also by the author of MGL. This supports both BLAS and CUBLAS (CUDA for GPUs) for solutions.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Finally, there&amp;rsquo;s the XLISP-STAT archive. Prior to Luke Tierney, the author of XLISP-Stat joining the core R team, XLISP-STAT was the dominate statistical computing platform. There&amp;rsquo;s heaps of stuff in the archive, most at least as good as what&amp;rsquo;s in base R, that could be ported to Lisp-Stat.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Common Lisp is a viable platform for statistics and machine learning. It isn&amp;rsquo;t (yet) quite as well organised as R or Python, but it&amp;rsquo;s all there.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/wei81o/numericals_performance_of_numpy_with_the_goodness/&#34;&gt;numericals - Performance of NumPy with the goodness of Common Lisp&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;numericals&lt;/code&gt; is &amp;ldquo;a high performance basic math library with
vectorized elementary and transcendental functions. It also provides
support for a numpy-like array object through &lt;code&gt;dense-arrays&lt;/code&gt; and
static-dispatch through the CLTL2 API.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;the post is about numericals, dense-arrays, magicl, numcl, py4cl/2…&lt;/li&gt;
&lt;li&gt;the author&amp;rsquo;s &lt;a href=&#34;https://gist.github.com/digikar99/ba2f0bb34021bfdc086b9c1c712ca228&#34;&gt;comparison and wish-list of features for a Common Lispy approach to a (better) Numpy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/melisgl/mgl-mat/&#34;&gt;MGL-MAT&lt;/a&gt; - a library for working with multi-dimensional arrays which supports efficient interfacing to foreign and CUDA code. BLAS and CUBLAS bindings are available.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/eigenhombre/hbook&#34;&gt;hbook&lt;/a&gt; - Text-based histograms in Common Lisp inspired by the venerable HBOOK histogramming library from CERN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://sourceforge.net/p/maxima/code/ci/master/tree/changelogs/ChangeLog-5.46.md&#34;&gt;Maxima 5.46 was released&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Maxima is a Computer Algebra System comparable to commercial systems like Mathematica and Maple. It emphasizes symbolic mathematical computation: algebra, trigonometry, calculus, and much more.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;see its frontends, for example &lt;a href=&#34;https://wxmaxima-developers.github.io/wxmaxima/&#34;&gt;WxMaxima&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Call to action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📢 &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/w6noju/uncle_stats_wants_you/&#34;&gt;Uncle Stats Wants You&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;web&#34;&gt;Web&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://screenshotbot.io/&#34;&gt;Screenshotbot&lt;/a&gt; (&lt;a href=&#34;https://github.com/screenshotbot/screenshotbot-oss&#34;&gt;Github&lt;/a&gt;) was released. It is &amp;ldquo;a screenshot testing service to tie with your existing Android, iOS and Web screenshot tests&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;It is straightforward to install with a Docker command. They offer more features and support with their paid service.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://camo.githubusercontent.com/22657cfd6c85d2ef97bd6612b051949f8a1a856b3fa88b48f540d974576a4f88/68747470733a2f2f73637265656e73686f74626f742e696f2f6173736574732f696d616765732f6c6f676f2d6461726b2e706e67&#34; style=&#34;max-width: 400px&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.licenseprompt.com/&#34;&gt;LicensePrompt&lt;/a&gt; was released. It is &amp;ldquo;a single place to track all recurring software and IT expenses and send relevant reminders to all interested people&amp;rdquo;. It&amp;rsquo;s built in CL, interface with HTMX.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://vishpat.github.io/lisp-rs-wasm/&#34;&gt;Lisp Interpreter in a browser using &lt;strong&gt;WASM&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://soi-disant.srht.site/entries/back-to-space.html&#34;&gt; Show HN: Common Lisp running natively over WebAssembly for the first time&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=31590819&#34;&gt;HN comments (64)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zgz8x8/jingle_common_lisp_web_framework_with_bells_and/&#34;&gt;jingle&lt;/a&gt;: Common Lisp web framework with bells and whistles (based on ningle)

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zk4jpl/jingle_demo_openapi_3x_spec_swagger_ui_docker_and/&#34;&gt;jingle demo&lt;/a&gt;: OpenAPI 3.x spec, Swagger UI, Docker and command-line interface app with jingle.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kjinho/ciao&#34;&gt;ciao&lt;/a&gt;: Ciao is an easy-to-use Common Lisp OAuth 2.0 client library. It is a port of the Racket OAuth 2.0 Client to Common Lisp.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/walpurgisnatch/stepster/&#34;&gt;stepster&lt;/a&gt;: a web scraping library, on top of Plump and Clss (new in QL)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/openrpc&#34;&gt;openrpc&lt;/a&gt;: Automatic OpenRPC spec generation, automatic JSON-RPC client building&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/zellerin/http2/&#34;&gt;HTTP/2 implementation in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skeletons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-cookieweb&#34;&gt;cl-cookieweb&lt;/a&gt;: my project skeleton to start web projects. Demo &lt;a href=&#34;https://www.youtube.com/watch?v=XFc513MJjos&#34;&gt;in video&lt;/a&gt;. I am cheating, the bulk of it was done in 2021.

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Provides a working toy web app with the Hunchentoot web server, easy-routes, Djula templates, styled with Bulma, based on SQLite, with migrations and an example table definition.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;if you don&amp;rsquo;t know where to start for web dev in CL, enjoy all the pointers of this starter kit and find your best setup.&lt;/li&gt;
&lt;li&gt;see also this &lt;a href=&#34;https://dnaeon.github.io/common-lisp-project-template/&#34;&gt;web template&lt;/a&gt; by @dnaeon, and check out all his other Lisp libraries.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bindings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;👍 &lt;a href=&#34;https://github.com/K1D77A/lisp-pay&#34;&gt;lisp-pay&lt;/a&gt;: Wrappers around various Payment Processors (Paypal, Stripe, Coinpayment)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/K1D77A/lunamech-matrix-api&#34;&gt;lunamech-matrix-api&lt;/a&gt;: Implementation of the Matrix API, LunaMech a Matrix bot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apps:&lt;/p&gt;

&lt;!-- - 📚 [OpenBookStore](https://github.com/OpenBookStore/openbookstore) --&gt;

&lt;!--   - a side project of mine, starts being usable. --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ackfock.com/&#34;&gt;Ackfock&lt;/a&gt; - a platform of mini agreements and mini memos of understanding (built with CLOG, closed source).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/KikyTokamuro/todolist-cl&#34;&gt;todolist-cl&lt;/a&gt;: a nice looking todolist with a web UI, written in Common Lisp (and by a newcomer to CL, to add credit)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don&amp;rsquo;t have lots of open-source apps to show. Mines are running in production and all is going well. I share everything on my blog posts. I also have an open-source one in development, but that&amp;rsquo;s for the 2023 showcase :D&lt;/p&gt;

&lt;h3 id=&#34;clog&#34;&gt;CLOG&lt;/h3&gt;

&lt;p&gt;🚀 The awesome novelty of 2022 I spoke of in the introduction is &lt;a href=&#34;https://github.com/rabbibotton/clog/&#34;&gt;CLOG&lt;/a&gt;, the Common Lisp Omnificent GUI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/rabbibotton/clog/tree/main/clogframe&#34;&gt;Native Desktop Executables for CLOG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/xegotj/clog_and_clog_builder_release_18_ide_for_common/&#34;&gt;CLOG and CLOG Builder Release 1.8 - IDE for Common Lisp and CLOG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/tl46of/would_it_be_cool_to_run_a_clog_app_on_mobile_you/&#34;&gt;CLOG on Android, APK download&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://i.redd.it/5021ipbttce91.png&#34; alt=&#34;The CLOG system browser&#34; /&gt;&lt;/p&gt;

&lt;p&gt;I know of one open-source consequent CLOG app: &lt;a href=&#34;https://codeberg.org/mmontone/mold-desktop/&#34;&gt;mold-desktop&lt;/a&gt;, in development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m developing a programmable desktop and a bookmarks manager application with CLOG. I think I know one of the things that make CLOG user interfaces so easy to develop. It is that they are effortlessly composable. That&amp;rsquo;s it for now :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;@mmontone&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://preview.redd.it/18lns1ijizc91.png?width=1919&amp;format=png&amp;auto=webp&amp;s=c103d33c22978ce8d2351de4cbf71638fe6286cf&#34; style=&#34;max-width: 600px&#34;/&gt;&lt;/p&gt;

&lt;!-- ## Other projects --&gt;

&lt;!-- - [Lisp Star: a star-shaped pendant that you can program in Lisp to make its six coloured LEDs twinkle in different patterns](http://www.technoblogy.com/show?2AMW) --&gt;

&lt;h2 id=&#34;new-releases&#34;&gt;New releases&lt;/h2&gt;

&lt;p&gt;There are lots of awesome projects in music composition, including OpusModus and OpenMusic which saw new releases. I also like to cite &lt;a href=&#34;https://scorecloud.com/&#34;&gt;ScoreCloud&lt;/a&gt;, a mobile app built with LispWorks, where you whistle, sing or play your instrument, and the app writes the music score O_o&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎵 &lt;a href=&#34;https://opusmodus.com/&#34;&gt;Opusmodus 3.0, Music Composition System, macOS Intel &amp;amp; Apple Silicon native, based on LispWorks, just released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;🎵 &lt;a href=&#34;https://github.com/openmusic-project/openmusic/releases/tag/v7.0&#34;&gt;OpenMusic 7.0, now also native for M1 Macs, visual programming language designed for music composition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://spwhitton.name/blog/entry/consfigurator_1.0.0/&#34;&gt;Consfigurator, a Common Lisp based declarative configuration management system, reaches v1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/phantomics/april/releases/tag/v1.0&#34;&gt;April 1.0 released&lt;/a&gt; - APL in Common Lisp.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hiphish.github.io/blog/2022/10/16/cl-cmark-approaching-stable/&#34;&gt;cl-cmark approaching stable release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/russell/cl-git&#34;&gt;cl-git: a Common Lisp CFFI interface to the libgit2 library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.autistici.org/interzona/tinmop.html&#34;&gt;tinmop 0.9.9.1, a terminal client for gopher, gemini, kami and pleroma.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;look here for how to build full-screen terminal applications in Common Lisp.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/tt1r9l/clingon_new_release_new_features_commandline/&#34;&gt;clingon - new release, new features (command-line options parser)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;a full-featured options parser. Supports sub-commands, bash and zsh completions, many arguments types…&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See awesome-cl and Cliki for more.&lt;/p&gt;

&lt;h2 id=&#34;re-discoveries&#34;&gt;(re) discoveries&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The math pastebin &lt;a href=&#34;https://mathb.in/3&#34;&gt;Mathb.in is written in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/zg4qfy/til_that_ptcs_creo_elementsdirect_3d_cad_modeling/&#34;&gt;TIL that PTC&amp;rsquo;s Creo Elements/Direct 3D CAD modeling software has a free version for Windows. &amp;ldquo;7+ million lines of Common Lisp code&amp;rdquo;, used by Eterna for their watches.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;that&amp;rsquo;s a huge software. 7 million lines. There&amp;rsquo;s a free version to try out!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;articles&#34;&gt;Articles&lt;/h1&gt;

&lt;h2 id=&#34;graphics&#34;&gt;Graphics&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://funcall.blogspot.com/2022/09/playing-with-raycasting.html&#34;&gt;Playing with raycasting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://funcall.blogspot.com/2022/08/playing-with-graphics.html&#34;&gt;Playing with graphics - a simple game with SDL2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://turtleware.eu/posts/Multipass-Translator-for-CLIM.html&#34;&gt;Multipass Translator for CLIM &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://turtleware.eu/posts/Implementing-a-simpleminded-REPL-from-scratch.html&#34;&gt;McCLIM: Implementing a simpleminded REPL from scratch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;tooling&#34;&gt;Tooling&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/zakbpg/debugging_lisp_trace_options_break_on_conditions/&#34;&gt;Debugging Lisp: trace options, break on conditions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=34252796#34279723&#34;&gt;HN comments (28)&lt;/a&gt;, I learned, again, new tips.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.djha.skin/p/developing-common-lisp-using-gnu-screen-rlwrap-and-vim/&#34;&gt;Developing Common Lisp using GNU Screen, Rlwrap, and Vim&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;again, learned new tips. The &lt;code&gt;--remember&lt;/code&gt; flag of &lt;code&gt;rlwrap&lt;/code&gt; allows to TAB-complete whatever was previously typed at the prompt. That&amp;rsquo;s dumb autocompletion, but autocompletion nonetheless. My &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/blob/master/exercises/chapter%201%20-%20getting%20started/rlwrap-enhanced.md&#34;&gt;summary&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.n16f.net/blog/configuring-slime-cross-referencing/&#34;&gt;Configuring Slime cross-referencing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.n16f.net/blog/slime-compilation-tips/&#34;&gt;SLIME Compilation Tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lisp-tips/lisp-tips/issues/38&#34;&gt;How to save lisp and die from Slime or Sly. trivial-dump-core&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;that may be super useful, at least if answers a question everybody has one time or another. I should try it more.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/uyubo1/how_to_approach_a_lisp_sandbox_environment/&#34;&gt;How to approach a Lisp sandbox environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/zqsv3w/log4cl_questions/&#34;&gt;log4cl questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/stumpwm/comments/zgigdt/a_stumpwm_debugger/&#34;&gt;A StumpWM debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zfkiem/windows_environment_for_sbcl/&#34;&gt;Windows environment for SBCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/thspgt/securing_quicklisp_through_mitmproxy/&#34;&gt;Securing Quicklisp through mitmproxy&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;because Quicklisp doesn&amp;rsquo;t use HTTPS. Here&amp;rsquo;s how to add security. The new CLPM uses HTTPS.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://susam.net/blog/lisp-in-vim.html&#34;&gt;Lisp in Vim&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;scripting&#34;&gt;Scripting&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://fukamachi.hashnode.dev/day-3-roswell-common-lisp-scripting&#34;&gt;Day 3: Roswell: Common Lisp scripting&lt;/a&gt;, by E. Fukamachi.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fukamachi.hashnode.dev/qlot-tutorial-with-docker&#34;&gt;Qlot tutorial with Docker&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/qlot&#34;&gt;Qlot v1.0.0&lt;/a&gt; was officially released.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fukamachi.hashnode.dev/day-4-roswell-how-to-make-roswell-scripts-faster&#34;&gt;Day 4: Roswell: How to make Roswell scripts faster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fukamachi.hashnode.dev/day-5-roswell-hidden-feature-of-s-option&#34;&gt;Day 5: Roswell: Hidden feature of &amp;ldquo;-s&amp;rdquo; option&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zwtfak/writing_scripts_in_lisp/&#34;&gt;Writing scripts in lisp?&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;a legitimate question. Many tips.&lt;/li&gt;
&lt;li&gt;where I show my very new and un-released &lt;a href=&#34;https://ciel-lang.github.io/CIEL/#/scripting&#34;&gt;CIEL scripting&lt;/a&gt; facility. Batteries included for Common Lisp. That&amp;rsquo;s for 2023 but you can be an early adopter :p&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zosu50/lisp_for_unixlike_systems/&#34;&gt;Lisp for Unix-like systems&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;in particular, read &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zosu50/lisp_for_unixlike_systems/j0owuqn/&#34;&gt;this answer by /u/lispm&lt;/a&gt; to learn about past and present attempts and solutions.&lt;/li&gt;
&lt;li&gt;will the OP manage to make WCL work? &amp;ldquo;WCL: Delivering efficient Common Lisp applications under Unix&amp;rdquo;, an implementation &amp;ldquo;tailored to zillions of small Lisp programs. Make sure that much of Lisp is shared memory. Be able to create shared memory libraries/applications&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zopsxq/sbcl_is_there_a_way_to_detect_if_lisp_code_was/&#34;&gt;(SBCL) Is there a way to detect if lisp code was run by &amp;ndash;script vs interactively?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;around-the-language&#34;&gt;Around the language&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://coalton-lang.github.io/20220906-quantum-compiler/&#34;&gt;Using Coalton to Implement a Quantum Compiler&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Coalton brings Haskell-like type checking on top of Common Lisp. Groundbreaking. They use it for their quantum compiler.&lt;/li&gt;
&lt;li&gt;it is still under development and there is &lt;a href=&#34;https://discord.com/invite/cPb6Bc4xAH&#34;&gt;their Discord&lt;/a&gt; to talk about it.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/ztzekh/eliminating_clos_for_a_45x_speedup/&#34;&gt;Eliminating CLOS for a 4.5x speedup&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;sometimes it&amp;rsquo;s easy, use a struct.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tfeb.org/fragments/2022/12/16/the-empty-list/&#34;&gt;The empty list.&lt;/a&gt; &amp;ldquo;Someone has been getting really impressively confused and cross on reddit about empty lists, booleans and so on in Common Lisp, which led us to a discussion about what the differences really are. Here’s a summary which we think is correct.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/zfna4y/are_there_any_tutorials_or_examples_people_would/&#34;&gt;Are there any tutorials or examples people would recommend to get started with unit testing common lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/wylmfx/fun_with_macros_dofile/&#34;&gt;Fun with Macros: Do-File&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://funcall.blogspot.com/2022/07/series-tips-and-tricks.html&#34;&gt;Series tips and tricks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/phoe/articles/blob/main/2022-01-29-static-let/static-let.md&#34;&gt;STATIC-LET, Or How I Learned To Stop Worrying And Love LOAD-TIME-VALUE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;History:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://informatimago.free.fr/i/develop/lisp/com/informatimago/small-cl-pgms/wang.html&#34;&gt;Old LISP programs still run in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;web-related&#34;&gt;Web related&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://dnaeon.github.io/common-lisp-web-dev-ningle-middleware/&#34;&gt;Common Lisp web development and the road to a middleware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/z8s9o8/lisp_for_the_web_building_one_standalone_binary/&#34;&gt;Lisp for the web: building one standalone binary with foreign libraries, templates and static assets&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;what I managed to do here, with the help of the community, represents a great step forward for my Lisp web stack.&lt;/li&gt;
&lt;li&gt;I can build a standalone binary for my web app, containing all static assets (a patch was required for the Djula HTML templating engine), so I can just &lt;code&gt;rsync&lt;/code&gt; it to my server and it works.&lt;/li&gt;
&lt;li&gt;a standalone binary is easy to integrate into an Electron window. Stay tuned.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/xetci2/lisp_for_the_web_deploying_with_systemd_gotchas/&#34;&gt;Lisp for the web: deploying with Systemd, gotchas and solutions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;all the little gotchas I faced are now google-able.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fukamachi.hashnode.dev/woo-a-high-performance-common-lisp-web-server&#34;&gt;Woo: a high-performance Common Lisp web server&lt;/a&gt;, by E. Fukamachi.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/http-over-unix-sockets-in-common-lisp-4l72&#34;&gt;HTTP over unix sockets in Common Lisp&lt;/a&gt;. By the same author:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/using-tailwindcss-in-common-lisp-web-apps-without-nodejs-tooling-3a8m&#34;&gt;Using TailwindCSS in Common Lisp web apps without Node.js tooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/using-svgs-in-common-lisp-web-apps-with-djula-5f00&#34;&gt;Using SVGs in Common Lisp web apps with Djula&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/create-a-common-lisp-web-app-using-ningle-1oj7&#34;&gt;Create a Common Lisp Web app using ningle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/how-to-use-environment-variables-with-cl-dotenv-in-a-common-lisp-web-app-5eb5&#34;&gt;Using environment variables with cl-dotenv in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/mito-an-orm-for-common-lisp-1n8n&#34;&gt;Mito: An ORM for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dev.to/rajasegar/running-docker-commands-from-common-lisp-repls-350p&#34;&gt;Running docker commands from Common Lisp REPLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;he also put up several little examples of a Common Lisp web app with HTMX, such as &lt;a href=&#34;https://github.com/rajasegar/cl-beers&#34;&gt;cl-beer&lt;/a&gt;. His stack: Caveman, Djula templates, HTMX for the interactivity. Thanks again, they are super useful.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hiphish.github.io/blog/2022/10/02/a-new-static-site-generator/&#34;&gt;A new static site generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/ze2n7u/web_development_with_cl_backend_and_clojurescript/&#34;&gt;Web Development with CL Backend and ClojureScript Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/wr0b6c/update_on_grpc_server/&#34;&gt;Update on gRPC Server&lt;/a&gt; - gRPC now has the ability to create servers based on protocol buffer service descriptors.&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://observablehq.com/@m-g-r/almost-600000-entries-per-second-from-lisp-to-accumulo&#34;&gt;Almost 600,000 entries per second from Lisp to Apache Accumulo over Apache Thrift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/clog-contest/&#34;&gt;Writing an interactive web app in Common Lisp: Hunchentoot then CLOG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sabracrolleton.github.io/json-review.html&#34;&gt;Review of CL Json Libraries, updated 15 Jan 2022&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Call for action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📢 &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/ykbi3x/jacl_call_for_collaboration/&#34;&gt;JACL call for collaboration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;other-articles&#34;&gt;Other articles&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://borretti.me/article/astronomical-calculations-for-hard-sf-common-lisp&#34;&gt;Astronomical Calculations for Hard Science Fiction in Common Lisp, by Fernando Borretti&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=34058658&#34;&gt;HN comments (42)&lt;/a&gt; (yes, 42)&lt;/li&gt;
&lt;li&gt;we miss you Fernando. Oh, he just released a new library: &lt;a href=&#34;https://github.com/eudoxia0/lcm&#34;&gt;lcm&lt;/a&gt;: &amp;ldquo;Manage your system configuration in Common Lisp. Think of it as Ansible, for your localhost&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;👀 &lt;a href=&#34;https://maxtaylor.dev/posts/2022/12/lisp-repl&#34;&gt;A LISP REPL Inside ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.shaka.today/freebsd-jail-quick-setup-with-networking-2022/&#34;&gt;FreeBSD Jail Quick Setup with Networking for a Common Lisp environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://arxiv.org/html/2205.11103&#34;&gt;Proceedings&lt;/a&gt;, Seventeenth International Workshop on the &lt;strong&gt;ACL2 Theorem Prover&lt;/strong&gt; and its Applications, 2022.

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cs.utexas.edu/users/moore/acl2/v8-5/combined-manual/index.html?topic=ACL2____NOTE-8-5&#34;&gt;ACL2 v8.5&lt;/a&gt; was released this year too.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://retro-style.software-by-mabe.com/blog/House+automation+tooling+-+Part+2+-+Getting+Serial&#34;&gt;Case study - house automation tool - part 2 - getting serial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;screencasts-and-podcasts&#34;&gt;Screencasts and podcasts&lt;/h1&gt;

&lt;p&gt;New videos by me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/debugging-lisp-fix-and-resume-a-program-from-any-point-in-stack/&#34;&gt;Debugging Lisp: fix and resume a program from any point in stack 🎥&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=TAtwcBh1QLg&#34;&gt;How to request the GitHub API: demo of Dexador, Jonathan, Shasht (and Serapeum), livecoding in Emacs and SLIME.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/XFc513MJjos&#34;&gt;How to create, run, build and load a new Lisp project&lt;/a&gt;, with my fully-featured project skeleton.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=KsHxgP3SRTs&#34;&gt;Interactively Fixing Failing Tests in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;by Gavin Freeborn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/GWdf1flcLoM&#34;&gt;Why Learn Lisp In 2022?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtube.com/watch?v=M4qj2ictRpg&amp;amp;feature=share&#34;&gt;Why Are Lisp Macros So Great!?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=AfY_zGR_QBI&#34;&gt;Lisp Is More Than Just A Language It&amp;rsquo;s An Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtube.com/watch?v=QHwghMNKVtg&amp;amp;feature=share&#34;&gt;Rewrite Your Scripts In LISP - with Roswell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/LqBbGFMPcDI&#34;&gt;Creating Your First Lisp Project - Quicklisp, asdf, and Packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtube.com/watch?v=0DLdQ6yb7h8&#34;&gt;Unleash the REPL with SLY&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/Ph8M8ThBgPc&#34;&gt;Lem: what if Emacs was multithreaded&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;KONS-9 series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=nSJcuOLmkl8&#34;&gt;Kaveh&amp;rsquo;s Common Lisp Lesson 01: points and shapes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/WFa4Xqcisrs&#34;&gt;Common Lisp OpenGL programming tutorial #12 - Animation &amp;amp; Hierarchies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLOG series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtube.com/watch?v=jEBDwjMnFXE&#34;&gt;CLOG Extra 3 - The CLOG Project System for CLOG and NON-CLOG projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtube.com/watch?v=CgTJMxsz3EY&#34;&gt;CLOG Extra 4 - All about panels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/w4zwm3/common_lisp_repl_style_dev_visually_with_clog/&#34;&gt;Repl Style. Dev &lt;em&gt;visually&lt;/em&gt; with CLOG Builder&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;This is amazing work! Having Pharo/Smalltalk capabilities with Common Lisp is fascinating.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CL study group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=oEjdONXZP1o&#34;&gt;Roswell (part II)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- by Josh Betts: --&gt;

&lt;!-- - [A CL website from scratch](https://youtu.be/f71d5Og0jIo)  No alt-right frog mascot, thanks. --&gt;

&lt;p&gt;Others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=RCWiqrdGcOs&#34;&gt;Common Lisp Game of Life visualisation with LispWorks and CAPI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/wCHnb8pvneE&#34;&gt;Nyxt on GambiConf (The hacker&amp;rsquo;s power-browser, written in Common Lisp)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=UQZusJynjiM&#34;&gt;Far and Away the Simplest Tutorial on Macros&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and of course, find 3h48+ of condensed Lisp content &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;on my Udemy video course&lt;/a&gt;! (I&amp;rsquo;m still working on new content, as a student you get updates).&lt;/p&gt;

&lt;p&gt;Aside screncasts, some &lt;strong&gt;podcasts&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://corecursive.com/lisp-in-space-with-ron-garret/&#34;&gt;CORECURSIVE #076: LISP in Space, With Ron Garret ← a podcast, trascribed with pictures&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=31234338&#34;&gt;HN comments (98)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;same topic: &lt;a href=&#34;https://thenewstack.io/nasa-programmer-remembers-debugging-lisp-in-deep-space/&#34;&gt;NASA Programmer Remembers Debugging Lisp in Deep Space&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.arraycast.com/episodes/episode23-andrew-sengul&#34;&gt;The Array Cast - Andrew Sengul, creator of the April language tells us about the advantages of combining Lisp and APL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/jBBS4FeY7XM&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;h1 id=&#34;other-discussions&#34;&gt;Other discussions&lt;/h1&gt;

&lt;h2 id=&#34;community&#34;&gt;Community&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;💌 &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/y6xpxr/impressions_of_common_lisp_and_the_lisp_community/&#34;&gt;Impressions of Common Lisp and the Lisp Community&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;So, thank you. I’m glad I found this group (and some other Lisp groups) on Reddit. You guys are a real blessing.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.timmons.dev/posts/cl-community-norms.html&#34;&gt;CL Community(?) Norms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/zanm37/in_what_domains_is_common_lisp_used_2022/&#34;&gt;In what domains is common lisp used in 2022?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/zx9qnq/what_are_you_working_on/&#34;&gt;What are you working on?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/ystf9s/a_brief_interview_with_common_lisp_creator_dr/&#34;&gt;A brief interview with Common Lisp creator Dr. Scott Fahlman&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;learning-lisp&#34;&gt;Learning Lisp&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/zagmm3/advice_on_professional_development_in_common_lisp/&#34;&gt;Advice on professional development in Common Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/z4rev7/trying_to_get_into_lisp_feeling_overwhelmed/&#34;&gt;Trying to get into Lisp, Feeling overwhelmed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/yydgrf/looking_for_good_common_lisp_projects_on_github/&#34;&gt;Looking for good common lisp projects on github to read?&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;this &lt;a href=&#34;https://github.com/search?p=2&amp;amp;q=defclass+user%3A40ants+user%3Aruricolist+user%3Ashinmera+user%3Ashirakumo+user%3Aedicl+language%3A%22Common+Lisp%22&amp;amp;type=Code&#34;&gt;GitHub advanced search&lt;/a&gt; searches for &lt;code&gt;defclass&lt;/code&gt; in 4 users projects: Shinmera, 40ants, Ruricolist, edicl (maintained Edi Weitz libraries):&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/yw8jgl/teach_lisp_to_high_schoolers/&#34;&gt;Teach lisp to high schoolers?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/yq2t4r/why_buy_lispworks/&#34;&gt;Why buy LispWorks?&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;it&amp;rsquo;s expensive (there&amp;rsquo;s a free limited edition), but all this feedback is much interesting.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/xqibzx/writing_robust_software_in_cl/&#34;&gt;Writing robust software in CL&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;talking Erlang, Actors libraries.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ruricolist/moira&#34;&gt;Moira&lt;/a&gt; -  Monitor and restart background threads.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/vz9l55/what_should_a_new_programmer_writing_in_common/&#34;&gt;What should a new programmer writing in Common Lisp know about security?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;common-lisp-vs&#34;&gt;Common Lisp VS …&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/z69ko5/what_were_the_lessons_you_learned_from/&#34;&gt;what were the lessons you learned from programming in Lisp that carried over to other languages (more on the imperative side)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/xo2ue7/for_seriousindustrialbusiness_use_in_what_ways_do/&#34;&gt;For serious/industrial/business use, in what ways do you think Common Lisp beat Clojure, and vice versa?&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;and: &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/wn7qhr/when_should_i_choose_common_lisp_over_clojure_for/&#34;&gt;When should I choose Common Lisp over Clojure (for business), and vice versa?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/vindarel/c1ef5e043773921e3b11d8f4fe1ca7ac&#34;&gt;Common Lisp VS Racket&lt;/a&gt; (openly biased over CL, with testimonies of lispers knowing both)

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=32723784&#34;&gt;HN comments (143)&lt;/a&gt;:  &amp;ldquo;I&amp;rsquo;m a heavy user of Common Lisp, and I only dabble in Racket from time to time. While Common Lisp is my tool of choice for a lot of reasons stated in the post, since the post largely skews favorably toward Common Lisp, I&amp;rsquo;ll offer two things that Racket shines at.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/digikar99/24decb414ddfa15a220b27f6748165d7&#34;&gt;Why not: from Common Lisp to Julia&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=32745318&#34;&gt;HackerNews comments (200)&lt;/a&gt; (for this post and the post it responds to)&lt;/li&gt;
&lt;li&gt;The author of the first post said he was &amp;ldquo;migrating from Common Lisp to Julia as [his] primary programming language&amp;rdquo;. He was starting &amp;ldquo;to grow increasingly frustrated with various aspects of the language&amp;rdquo; and the CL ecosystem. Many of his arguments were harsh towards CL and didn&amp;rsquo;t mention existing better alternatives.&lt;/li&gt;
&lt;li&gt;Two months later, in &lt;a href=&#34;https://mfiano.net/posts/2022-11-05-programming-languages-i-use/&#34;&gt;another blog
post&lt;/a&gt;,
he admits the previous article &amp;ldquo;was unfair to both languages&amp;rdquo;, and
while &amp;ldquo;[he] is still mostly using Julia&amp;rdquo;, &amp;ldquo;Common Lisp is still on the table for [him]&amp;ldquo;.&lt;/li&gt;
&lt;li&gt;On
&lt;a href=&#34;https://irclog.tymoon.eu/libera/%23commonlisp?around=1669837028#1669837028&#34;&gt;LiberaChat&lt;/a&gt;,
he says he&amp;rsquo;s back from Julia to Common Lisp: &amp;ldquo;As of yesterday, I&amp;rsquo;m
back to making libraries in CL. I cannot consider Julia as a
serious language anymore, for it has deceived me after 7 years of
research.&amp;rdquo;
&lt;!-- - In 2017, he tried migrating to Racket, but also came back to CL. --&gt;&lt;/li&gt;
&lt;li&gt;Welcome back and thanks to him for the past and future CL libraries.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/wgdy51/is_lisp_too_malleable_to_use_for_serious/&#34;&gt;Is Lisp too malleable to use for serious development?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/naver/lispe/wiki/6.16-Why-Lisp&#34;&gt;Why Lisp?&lt;/a&gt; (&lt;a href=&#34;https://github.com/naver/lispe/wiki/6.16-Pourquoi-Lisp&#34;&gt;version française&lt;/a&gt;). &amp;ldquo;We will show how our own LispE interpreter was implemented.&amp;rdquo;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=33462454&#34;&gt;HN comments (200)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Thanks everyone, happy lisping and see you around!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Debugging Lisp: fix and resume a program from any point in stack 🎥</title>
      <link>/blog/debugging-lisp-fix-and-resume-a-program-from-any-point-in-stack/</link>
      <pubDate>Tue, 06 Dec 2022 12:47:04 +0100</pubDate>
      
      <guid>/blog/debugging-lisp-fix-and-resume-a-program-from-any-point-in-stack/</guid>
      <description>&lt;p&gt;You are doing god&amp;rsquo;s work on a time-intensive computation, but your final step errors out :S Are you doomed to start everything from zero, and wait again for this long process? No! Find out.&lt;/p&gt;

&lt;p&gt;I show this with Emacs and Slime, then with the &lt;a href=&#34;https://github.com/lem-project/lem/&#34;&gt;Lem editor&lt;/a&gt; (ready-to-use for CL, works with many more languages thanks to its LSP client).&lt;/p&gt;

&lt;p&gt;(This video is so cool :D Sound on)&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/jBBS4FeY7XM&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;We use the built-in Common Lisp interactive debugger that lets us restart one precise frame from the call stack. Once you get the debugger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;press &amp;ldquo;v&amp;rdquo; on a frame to go to the corresponding source file&lt;/li&gt;
&lt;li&gt;fix the buggy function, compile it again (C-c C-c in Slime)&lt;/li&gt;
&lt;li&gt;come back to the debugger, place the point on the frame you want to try again, press &amp;ldquo;r&amp;rdquo; (sldb-restart-frame, see your editor&amp;rsquo;s menu)&lt;/li&gt;
&lt;li&gt;see everything succeed. You did &lt;em&gt;not&lt;/em&gt; restart everything from zero.&lt;/li&gt;
&lt;li&gt;if you don&amp;rsquo;t see some function calls and variables in the debugger, compile your code with max debug settings (&lt;code&gt;C-u C-c C-c&lt;/code&gt; in Slime).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/debugging.html&lt;/a&gt; - see how to break and step, how to trace function calls, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other videos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=XFc513MJjos&#34;&gt;How to create a full-featured Common Lisp project&lt;/a&gt; with &lt;a href=&#34;https://github.com/vindarel/cl-cookieproject&#34;&gt;my project generator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=TAtwcBh1QLg&#34;&gt;How to call a REST API in Common Lisp - example with the GitHub API&lt;/a&gt;, sending HTTP requests, parsing JSON, building a binary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you learned something!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;img src=&#34;/images/debugging-python-VS-lisp.png&#34; alt=&#34;Debugging a complex stacktrace in Python VS Common Lisp (unknown author)&#34; /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Debugging Lisp: trace options, break on conditions</title>
      <link>/blog/debugging-lisp-trace-options-break-on-conditions/</link>
      <pubDate>Fri, 02 Dec 2022 11:08:27 +0100</pubDate>
      
      <guid>/blog/debugging-lisp-trace-options-break-on-conditions/</guid>
      <description>

&lt;p&gt;Those are useful Common Lisp debugging tricks. Did you know about trace options?&lt;/p&gt;

&lt;p&gt;We see how &lt;code&gt;trace&lt;/code&gt; accepts options. Especially, we see how we can &lt;code&gt;break&lt;/code&gt; and invoke the interactive debugger before or after a function call, how we can break on a condition (&amp;ldquo;this argument equals 0&amp;rdquo;) and how we can enrich the trace output. But we only scratch the surface, more options are documented on their upstream documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.sbcl.org/manual/index.html#Function-Tracing&#34;&gt;SBCL trace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ccl.clozure.com/manual/chapter4.2.html&#34;&gt;CCL trace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/lw80/lw/lw-tracer-ug-2.htm&#34;&gt;LispWorks trace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://franz.com/support/documentation/current/doc/debugging.htm#tracer-1&#34;&gt;Allegro trace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px; margin-top: 1em;&#34;&gt;
&lt;strong&gt;INFO:&lt;/strong&gt;
You&#39;d better read this on &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html&#34;&gt;the Common Lisp Cookbook&lt;/a&gt;, that&#39;s where it will receive updates.
&lt;/div&gt;



&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#trace---basics&#34;&gt;Trace - basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#trace-options---break-and-invoke-the-debugger&#34;&gt;Trace options - break and invoke the debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#break-on-a-condition&#34;&gt;break on a condition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-options&#34;&gt;Other options&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#trace-on-conditions&#34;&gt;Trace on conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#trace-if-called-from-another-function&#34;&gt;Trace if called from another function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#enrich-the-trace-output&#34;&gt;Enrich the trace output&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-remark&#34;&gt;Closing remark&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;trace-basics&#34;&gt;Trace - basics&lt;/h1&gt;

&lt;p&gt;But let&amp;rsquo;s first see a recap&amp;rsquo; of the &lt;code&gt;trace&lt;/code&gt; macro. Compared to the previous Cookbook content, we just added that &lt;code&gt;(trace)&lt;/code&gt; alone returns a list of traced functions.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/m_tracec.htm&#34;&gt;trace&lt;/a&gt; allows us to see when a function was called, what arguments it received, and the value it
returned.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun factorial (n)
  (if (plusp n)
    (* n (factorial (1- n)))
    1))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To start tracing a function, just call &lt;code&gt;trace&lt;/code&gt; with the function name
(or several function names):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace factorial)

(factorial 2)
  0: (FACTORIAL 3)
    1: (FACTORIAL 2)
      2: (FACTORIAL 1)
        3: (FACTORIAL 0)
        3: FACTORIAL returned 1
      2: FACTORIAL returned 1
    1: FACTORIAL returned 2
  0: FACTORIAL returned 6
6

(untrace factorial)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To untrace all functions, just evaluate &lt;code&gt;(untrace)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get a list of currently traced functions, evaluate &lt;code&gt;(trace)&lt;/code&gt; with no arguments.&lt;/p&gt;

&lt;p&gt;In Slime we have the shortcut &lt;code&gt;C-c M-t&lt;/code&gt; to trace or untrace a
function.&lt;/p&gt;

&lt;p&gt;If you don&amp;rsquo;t see recursive calls, that may be because of the
compiler&amp;rsquo;s optimizations. Try this before defining the function to be
traced:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(declaim (optimize (debug 3)))  ;; or C-u C-c C-c to compile with maximal debug settings.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output is printed to &lt;code&gt;*trace-output*&lt;/code&gt; (see the CLHS).&lt;/p&gt;

&lt;p&gt;In Slime, we also have an interactive trace dialog with &lt;code&gt;M-x
slime-trace-dialog&lt;/code&gt; bound to &lt;code&gt;C-c T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But we can do many more things than calling &lt;code&gt;trace&lt;/code&gt; with a simple argument.&lt;/p&gt;

&lt;h1 id=&#34;trace-options-break-and-invoke-the-debugger&#34;&gt;Trace options - break and invoke the debugger&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;trace&lt;/code&gt; accepts options. For example, you can use &lt;code&gt;:break t&lt;/code&gt; to invoke
the debugger at the start of the function, before it is called (more on break below):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace factorial :break t)
(factorial 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can define many things in one call to &lt;code&gt;trace&lt;/code&gt;. For instance,
options that appear before the first function name to trace are
&lt;em&gt;global&lt;/em&gt;, they affect all traced functions that we add afterwards. Here,
&lt;code&gt;:break t&lt;/code&gt; is set for every function that follows: &lt;code&gt;factorial&lt;/code&gt;, &lt;code&gt;foo&lt;/code&gt;
and &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace :break t factorial foo bar)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On the contrary, if an option comes after a function name, it acts as
a &lt;em&gt;local&lt;/em&gt; option, only for its &lt;em&gt;preceding&lt;/em&gt; function. That&amp;rsquo;s how we first
did. Below &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; come after, they are not affected by &lt;code&gt;:break&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace factorial :break t foo bar)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But do you actually want to &lt;code&gt;break&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; the function call or just
&lt;em&gt;after&lt;/em&gt; it? With &lt;code&gt;:break&lt;/code&gt; as with many options, you can choose. These
are the options for &lt;code&gt;:break&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:break form  ;; before
:break-after form
:break-all form ;; before and after
&lt;/code&gt;&lt;/pre&gt;



&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px; margin-top: 1em;&#34;&gt;
&lt;strong&gt;TIP:&lt;/strong&gt;
&lt;code&gt;form&lt;/code&gt; can be any form that evaluates to true. You can add any custom logic here.
&lt;/div&gt;



&lt;p&gt;Note that we explained the trace function of SBCL. Other
implementations may have the same feature with another syntax and
other option names.  For example, in LispWorks it is &amp;ldquo;:break-on-exit&amp;rdquo;
instead of &amp;ldquo;:break-after&amp;rdquo;, and we write &lt;code&gt;(trace (factorial :break t))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below are some other options but first, a trick with &lt;code&gt;:break&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&#34;break-on-a-condition&#34;&gt;break on a condition&lt;/h1&gt;

&lt;p&gt;The argument to an option can be any form. Here&amp;rsquo;s a trick, on SBCL, to
get the break window when we are about to call &lt;code&gt;factorial&lt;/code&gt;
with 0. &lt;code&gt;(sb-debug:arg 0)&lt;/code&gt; refers to &lt;code&gt;n&lt;/code&gt;, the first argument.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (trace factorial :break (equal 0 (sb-debug:arg 0)))
;; WARNING: FACTORIAL is already TRACE&#39;d, untracing it first.
;; (FACTORIAL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running it again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CL-USER&amp;gt; (factorial 3)
  0: (FACTORIAL 3)
    1: (FACTORIAL 2)
      2: (FACTORIAL 1)
        3: (FACTORIAL 0)

breaking before traced call to FACTORIAL:
   [Condition of type SIMPLE-CONDITION]

Restarts:
 0: [CONTINUE] Return from BREAK.
 1: [RETRY] Retry SLIME REPL evaluation request.
 2: [*ABORT] Return to SLIME&#39;s top level.
 3: [ABORT] abort thread (#&amp;lt;THREAD &amp;quot;repl-thread&amp;quot; RUNNING {1003551BC3}&amp;gt;)

Backtrace:
  0: (FACTORIAL 1)
      Locals:
        N = 1   &amp;lt;---------- n is still 1, we break before the call with 0.
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;other-options&#34;&gt;Other options&lt;/h1&gt;

&lt;h2 id=&#34;trace-on-conditions&#34;&gt;Trace on conditions&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;:condition&lt;/code&gt; enables tracing only if the condition in &lt;code&gt;form&lt;/code&gt; evaluates to true.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:condition form
:condition-after form
:condition-all form
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;If :condition is specified, then trace does nothing unless Form
evaluates to true at the time of the call. :condition-after is
similar, but suppresses the initial printout, and is tested when the
function returns. :condition-all tries both before and after.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;trace-if-called-from-another-function&#34;&gt;Trace if called from another function&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;:wherein&lt;/code&gt; can be super useful:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:wherein Names
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;If specified, Names is a function name or list of names. trace does nothing unless a call to one of those functions encloses the call to this function (i.e. it would appear in a backtrace.) Anonymous functions have string names like &amp;ldquo;DEFUN FOO&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;enrich-the-trace-output&#34;&gt;Enrich the trace output&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;:report Report-Type
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;If Report-Type is trace (the default) then information is reported
by printing immediately. If Report-Type is nil, then the only effect
of the trace is to execute other options (e.g. print or
break). Otherwise, Report-Type is treated as a function designator
and, for each trace event, funcalled with 5 arguments: trace depth
(a non-negative integer), a function name or a function object, a
keyword (:enter, :exit or :non-local-exit), a stack frame, and a
list of values (arguments or return values).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See also &lt;code&gt;:print&lt;/code&gt; to enrich the trace output:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In addition to the usual printout, the result of evaluating Form is printed at the start of the function, at the end of the function, or both, according to the respective option. Multiple print options cause multiple values to be printed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *counter* 0)
(defun factorial (n)
  (incf *counter*)
  (if (plusp n)
    (* n (factorial (1- n)))
    1))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;CL-USER&amp;gt; (trace factorial :print *counter*)
CL-USER&amp;gt; (factorial 3)
(FACTORIAL 3)
  0: (FACTORIAL 3)
  0: *COUNTER* = 0
    1: (FACTORIAL 2)
    1: *COUNTER* = 1
      2: (FACTORIAL 1)
      2: *COUNTER* = 2
        3: (FACTORIAL 0)
        3: *COUNTER* = 3
        3: FACTORIAL returned 1
      2: FACTORIAL returned 1
    1: FACTORIAL returned 2
  0: FACTORIAL returned 6
6
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;closing-remark&#34;&gt;Closing remark&lt;/h1&gt;

&lt;p&gt;As they say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;it is expected that implementations extend TRACE with non-standard options.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and we didn&amp;rsquo;t list all available options or parameters, so you should check out your implementation&amp;rsquo;s documentation.&lt;/p&gt;

&lt;p&gt;For more debugging tricks see the Cookbook and the links in it, the Malisper series have nice GIFs.&lt;/p&gt;

&lt;p&gt;I am also preparing a short screencast to show what we can do inside the debugger, stay tuned!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lisp for the web: building one standalone binary with foreign libraries, templates and static assets</title>
      <link>/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/</link>
      <pubDate>Mon, 28 Nov 2022 18:43:43 +0100</pubDate>
      
      <guid>/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/</guid>
      <description>

&lt;p&gt;In our previous entry, we saw how to deploy our web application with
Systemd, either from sources or with a binary. Now we&amp;rsquo;ll speak more
about this building process to produce &lt;strong&gt;one binary that contains
everything for our web app&lt;/strong&gt;. We&amp;rsquo;ll tackle 3 issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ship foreign libraries alongside your binary, such as &lt;code&gt;libreadline.so&lt;/code&gt; or &lt;code&gt;libsqlite3.so&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;include your Djula templates into your binary,&lt;/li&gt;
&lt;li&gt;serve static files from your binary, without reading the filesystem,&lt;/li&gt;
&lt;li&gt;and we&amp;rsquo;ll see my Gitlab CI recipe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows us to create a binary that is really easy to deploy, to ship to users or to embed in an external process such as an &lt;strong&gt;Electron window&lt;/strong&gt; (more on that later). Coming from Python and JS, what a dream!&lt;/p&gt;

&lt;p&gt;Now, I want to thank the people that helped me figure
these issues out and who wrote, fixed and extended these libraries: special shout-out to @mmontone for writing a Djula patch so quickly, @shinmera for Deploy and answering my many questions on Discord, @zulu.inoe for finding Hunchentoot answers, and everybody else on Discord for their help (@gavinok, @fstamour et all, sorry if I forgot) and all who dare asking questions to let everybody learn!&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;
- &lt;a href=&#34;#ship-foreign-libraries-the-need-of-deploy&#34;&gt;Ship foreign libraries: the need of Deploy&lt;/a&gt;
    - &lt;a href=&#34;#configuring-deploy-ignore-libssl-verbosity&#34;&gt;Configuring Deploy: ignore libssl, verbosity&lt;/a&gt;
    - &lt;a href=&#34;#remember-your-program-runs-on-another-users-machine&#34;&gt;Remember: your program runs on another user&amp;rsquo;s machine.&lt;/a&gt;
- &lt;a href=&#34;#telling-asdf-to-calm-down&#34;&gt;Telling ASDF to calm down&lt;/a&gt;
- &lt;a href=&#34;#embed-html-djula-templates-in-your-binary&#34;&gt;Embed HTML Djula templates in your binary&lt;/a&gt;
- &lt;a href=&#34;#serve-static-assets&#34;&gt;Serve static assets&lt;/a&gt;
- &lt;a href=&#34;#gitlab-ci&#34;&gt;Gitlab CI&lt;/a&gt;
- &lt;a href=&#34;#closing-remarks&#34;&gt;Closing remarks&lt;/a&gt;&lt;/p&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;ship-foreign-libraries-the-need-of-deploy&#34;&gt;Ship foreign libraries: the need of Deploy&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Shinmera/deploy&#34;&gt;Deploy&lt;/a&gt; is the way to go. If you used &lt;code&gt;asdf:make&lt;/code&gt; in your .asd system definition to create a binary already, you just need to change two things:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; my-project.asd
:defsystem-depends-on (:deploy)  ;; so you need to quickload deploy sometime before.
:build-operation &amp;quot;deploy-op&amp;quot;  ;; instead of program-op for asdf:make
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and those two lines stay the same:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;:build-pathname &amp;quot;my-application-name&amp;quot;
:entry-point &amp;quot;my-package:my-start-function&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;rsquo;s my Makefile target, where I &lt;code&gt;quickload&lt;/code&gt; Deploy before loading my app and calling &lt;code&gt;asdf:make&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;LISP ?= sbcl

build:
	$(LISP)	--non-interactive \
		--eval &#39;(ql:quickload &amp;quot;deploy&amp;quot;)&#39; \
		--load openbookstore.asd \
		--eval &#39;(ql:quickload :openbookstore)&#39; \
		--eval &#39;(asdf:make :openbookstore)&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a &lt;code&gt;bin/&lt;/code&gt; directory with our binary and the foreign libraries:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  -rwxr-xr-x  1 vindarel vindarel 130545752 Nov 25 18:48 openbookstore
  -rw-rw-r--  1 vindarel vindarel    294632 Aug  3 13:06 libreadline.so.7.0
  -rw-rw-r--  1 vindarel vindarel    319528 Aug 23 18:01 libreadline.so.8.0
  -rw-rw-r--  1 vindarel vindarel   1212216 Aug 24 16:42 libsqlite3.so.0.8.6
  -rw-rw-r--  1 vindarel vindarel    116960 Aug  3 13:06 libz.so.1.2.11
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We need to deploy this directory.&lt;/p&gt;

&lt;p&gt;When we start the binary, Deploy tells us what it is doing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./bin/openbookstore --datasource argentina lisp
 ==&amp;gt; Performing warm boot.
   -&amp;gt; Runtime directory is /home/vindarel/projets/openbookstore/openbookstore/bin/
   -&amp;gt; Resource directory is /home/vindarel/projets/openbookstore/openbookstore/bin/
 ==&amp;gt; Running boot hooks.
 ==&amp;gt; Reloading foreign libraries.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY READLINE&amp;gt;.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY SQLITE3-LIB&amp;gt;.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY LIBSSL&amp;gt;.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY LIBCRYPTO&amp;gt;.
 ==&amp;gt; Launching application.
OpenBookStore version 0.2-d2ac5f2
[…]
==&amp;gt; Epilogue.
==&amp;gt; Running quit hooks.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can configure Deploy.&lt;/p&gt;

&lt;h2 id=&#34;configuring-deploy-ignore-libssl-verbosity&#34;&gt;Configuring Deploy: ignore libssl, verbosity&lt;/h2&gt;

&lt;p&gt;You can silence the Deploy statuses by pushing &lt;code&gt;:deploy-console&lt;/code&gt; into the &lt;code&gt;*features*&lt;/code&gt; list, before calling &lt;code&gt;asdf:make&lt;/code&gt;. Add this to the Makefile:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;--eval &#39;(push :deploy-console *features*)&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now all seems well, you rsync your app to your server, run it and… you get a libssl error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;=&amp;gt; Deploying files to /home/vindarel/projets/myapp/commandes-collectivites/bin/
Unhandled SIMPLE-ERROR in thread #&amp;lt;SB-THREAD:THREAD &amp;quot;main thread&amp;quot; RUNNING
                                    {10007285B3}&amp;gt;:
  #&amp;lt;LIBRARY LIBCRYPTO&amp;gt; does not have a known shared library file path.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nicolas (@shinmera) explained that we typically want to import libssl or libcrypto
from the target system, that &amp;ldquo;deploying these libraries without them blowing
up on Linux is hard&amp;rdquo;. To do this, we ask Deploy to &lt;em&gt;not&lt;/em&gt; handle them. In the .asd:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+linux (deploy:define-library cl+ssl::libssl :dont-deploy T)
#+linux (deploy:define-library cl+ssl::libcrypto :dont-deploy T)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As a consequence, you now need to &lt;code&gt;quickload&lt;/code&gt; or &lt;code&gt;require&lt;/code&gt; &lt;code&gt;:cl+ssl&lt;/code&gt; before loading the .asd file, because of the &lt;code&gt;cl+ssl::libssl/libcrypto&lt;/code&gt; symbols at the top level.&lt;/p&gt;

&lt;p&gt;Nicolas built all this for his needs when working on his &lt;a href=&#34;https://github.com/shirakumo/trial&#34;&gt;Trial&lt;/a&gt; game engine and on his &lt;a href=&#34;https://kandria.com/&#34;&gt;Kandria game&lt;/a&gt; (soon on Steam!), check them out!&lt;/p&gt;

&lt;h2 id=&#34;remember-your-program-runs-on-another-user-s-machine&#34;&gt;Remember: your program runs on another user&amp;rsquo;s machine.&lt;/h2&gt;

&lt;p&gt;By this I mean that if you took the habit to use functions that locate
a project&amp;rsquo;s source directory (&lt;code&gt;asdf:system-source-directory&lt;/code&gt;,
&lt;code&gt;asdf:system-relative-pathname&lt;/code&gt;, for example when asking Hunchentoot to serve static assets, more on that below), then you need to re-write them, because your binary runs on another machine and it doesn&amp;rsquo;t run from sources, so ASDF, Quicklisp and friends are not installed, and your project(s) don&amp;rsquo;t have source directories, they are embedded in the binary.&lt;/p&gt;

&lt;p&gt;Use a &lt;code&gt;deploy:deployed-p&lt;/code&gt; runtime check if needed.&lt;/p&gt;

&lt;h1 id=&#34;telling-asdf-to-calm-down&#34;&gt;Telling ASDF to calm down&lt;/h1&gt;

&lt;p&gt;Now, we are very happy and confident, what could possibly go wrong? We run our app once again on our naked VPS:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./bin/myapp
 ==&amp;gt; Performing warm boot.
   -&amp;gt; Runtime directory is /home/debian/websites/app/myapp/bin/
   -&amp;gt; Resource directory is /home/debian/websites/app/myapp/bin/
 ==&amp;gt; Running boot hooks.
 ==&amp;gt; Reloading foreign libraries.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY LIBSSL&amp;gt;.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY LIBRT&amp;gt;.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY LIBOSICAT&amp;gt;.
   -&amp;gt; Loading foreign library #&amp;lt;LIBRARY LIBMAGIC&amp;gt;.
 ==&amp;gt; Launching application.
WARNING:
   You are using ASDF version 3.3.4.15 from
   #P&amp;quot;/home/vindarel/common-lisp/asdf/asdf.asd&amp;quot; and have an older version of ASDF
   (and older than 2.27 at that) registered at
   #P&amp;quot;/home/vindarel/common-lisp/asdf/asdf.asd&amp;quot;.

  [ long message ellided ]

;
; compilation unit aborted
;   caught 1 fatal ERROR condition
An error occured:
 Error while trying to load definition for system asdf from pathname
 /home/vindarel/common-lisp/asdf/asdf.asd:
    Couldn&#39;t load #P&amp;quot;/home/vindarel/common-lisp/asdf/asdf.asd&amp;quot;: file does not
    exist. ==&amp;gt; Epilogue.
 ==&amp;gt; Running quit hooks.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now ASDF wants to do what, update itself? Whatever it tries to do, it
crashes. Yes, this happens on the target host, when we run the
binary. Damn!&lt;/p&gt;

&lt;p&gt;The solution is easy, but it had to be documentend or google-able… Add this in your .asd to tell ASDF to not try to upgrade itself:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(deploy:define-hook (:deploy asdf) (directory)
  ;; Thanks again to Shinmera.
  (declare (ignorable directory))
  #+asdf (asdf:clear-source-registry)
  #+asdf (defun asdf:upgrade-asdf () nil))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By the way, if you want a one-liner to upgrade ASDF to 3.3.5 so that you can use package-local nicknames, &lt;a href=&#34;https://github.com/lisp-tips/lisp-tips/issues/40&#34;&gt;check this lisp tip&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;embed-html-djula-templates-in-your-binary&#34;&gt;Embed HTML Djula templates in your binary&lt;/h1&gt;

&lt;p&gt;Our binary now runs fine on our server: super great. But our app has another issue.&lt;/p&gt;

&lt;p&gt;I like very much &lt;a href=&#34;https://github.com/mmontone/djula/&#34;&gt;Djula
templates&lt;/a&gt;, maintained by
@mmontone. It is a traditional, no-surprises HTML templating system,
very similar to Django templates. It is easy to setup, it is very easy
to create custom filters, it has good error messages, both in the
browser window and on the Lisp REPL. It&amp;rsquo;s one of the most downloaded
Quicklisp libraries. Like Django templates, its philosophy is that it doesn&amp;rsquo;t allow a lot of computations in the
template. It encourages to prepare your data on the back-end,
so it is straightforward to process them in the templates. Sometimes
it is limiting, so for more flexibility I&amp;rsquo;d look at
&lt;a href=&#34;https://github.com/mmontone/ten/&#34;&gt;Ten&lt;/a&gt;. It isn&amp;rsquo;t as much used and
tested though (and I didn&amp;rsquo;t try it myself). If you want lispy templates, look at
&lt;a href=&#34;https://github.com/ruricolist/spinneret&#34;&gt;Spinneret&lt;/a&gt;. You can say
goodby to copy-pasting nice-looking HTML examples, though.&lt;/p&gt;

&lt;p&gt;However, by using Spinneret you would have not faced the following issue:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Djula reads templates from your file system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;and when your application runs on someone else&amp;rsquo;s machine, this is undefined behaviour.&lt;/p&gt;

&lt;p&gt;Until now, you had to deploy your web app from sources or, at least, you had to
send the HTML files to the server. This was the case until I talked
about this issue to Mariano. He sent a patch the day after.&lt;/p&gt;

&lt;p&gt;Now, we can choose: by default, Djula reads the HTML files from disk: very well. But now, when we build our binary, &lt;em&gt;we can ask Djula to build the templates in memory, so they are saved into the Lisp binary&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Normally, you only need to tell Djula where to find templates (&amp;ldquo;add a template directory&amp;rdquo;), then to compile them into a variable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; normal, file-system case.
(djula:add-template-directory (asdf:system-relative-pathname &amp;quot;webapp&amp;quot; &amp;quot;templates/&amp;quot;))
(defparameter +base.html+ (djula:compile-template* &amp;quot;base.html&amp;quot;))

;; and then, we render the template with (djula:render-template* nil +base.html+ …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This uses a &lt;code&gt;filesystem-template-store&lt;/code&gt;. In addition, it recompiles templates on change. This can be turned off as we&amp;rsquo;ll see.&lt;/p&gt;

&lt;p&gt;For our binary, we need to set Djula&amp;rsquo;s &lt;code&gt;*current-store*&lt;/code&gt; to a &lt;code&gt;memory-template-store&lt;/code&gt; AND we need to turn off the &lt;code&gt;djula:*recompile-templates-on-change*&lt;/code&gt; setting. Then, we need to compile all the templates of our application, and save our binary.&lt;/p&gt;

&lt;p&gt;I actually do all this at the top-level of my web.lisp file. By
default I load the app for development, and if we find a custom
&amp;ldquo;feature&amp;rdquo;, that is added by the &amp;ldquo;build&amp;rdquo; target of the Makefile, we
compile templates in memory.&lt;/p&gt;

&lt;p&gt;So, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;in the &amp;ldquo;build&amp;rdquo; target of my Makefile, I push a new setting in the &lt;code&gt;*features*&lt;/code&gt; list:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;--eval &#39;(push :djula-binary *features*)&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;in my web.lisp, I check for this setting (with &lt;code&gt;#+djula-binary&lt;/code&gt;) and I create either a filetemplate store or a memory store. This is written at the top-level so it will be executed when we &lt;code&gt;load&lt;/code&gt; the file. We can probably come up with better ergonomics.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will be executed when I quickload my app in the &lt;code&gt;build&lt;/code&gt; target of the Makefile, following the one above.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    --eval &#39;(ql:quickload :openbookstore)&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf djula:*current-store*
      (let ((search-path (list (asdf:system-relative-pathname &amp;quot;openbookstore&amp;quot;
                                                              &amp;quot;src/web/templates/&amp;quot;))))
        #-djula-binary
        (progn
          (uiop:format! t &amp;quot;~&amp;amp;Openbookstore: compiling templates in file system store.~&amp;amp;&amp;quot;)
          ;; By default, use a file-system store and reload templates during development.
          (setf djula:*recompile-templates-on-change* t)
          (make-instance &#39;djula:filesystem-template-store
		         :search-path search-path))

        ;; But, if this setting is set to NIL at load time, from the Makefile,
        ;; we are building a standalone binary: use an in-memory template store.
        ;;
        ;; We also need to NOT re-compile templates on change.
        #+djula-binary
        (progn
          (uiop:format! t &amp;quot;~&amp;amp;Openbookstore: compiling templates in MEMORY store.~&amp;amp;&amp;quot;)
          (setf djula:*recompile-templates-on-change* nil)
          (make-instance &#39;djula:memory-template-store :search-path search-path))))
&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
&lt;li&gt;compile all the templates. If you used a web framework (or started to develop yours), you might have used a shortcut: calling a &lt;code&gt;render&lt;/code&gt; function which takes the name of a template as a string for argument. I&amp;rsquo;m thinking about Caveman:&lt;/li&gt;
&lt;/ol&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;@route GET &amp;quot;/&amp;quot;
(defun index ()
  (render #P&amp;quot;index.tmpl&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This strings denotes the name of the template. For a standalone binary, we need to compile the template before. That&amp;rsquo;s why Djula shows how to define and compile our templates:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter +base.html+ (djula:compile-template* &amp;quot;base.html&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You need this line for every template of your application:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Compile and load templates (as usual).
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defparameter +base.html+ (djula:compile-template* &amp;quot;base.html&amp;quot;))
(defparameter +dashboard.html+ (djula:compile-template* &amp;quot;dashboard.html&amp;quot;))
(defparameter +search.html+ (djula:compile-template* &amp;quot;search.html&amp;quot;))
(defparameter +stock.html+ (djula:compile-template* &amp;quot;stock.html&amp;quot;))
(defparameter +card-page.html+ (djula:compile-template* &amp;quot;card-page.html&amp;quot;))
(defparameter +card-stock.html+ (djula:compile-template* &amp;quot;card-stock.html&amp;quot;))
(defparameter +card-create.html+ (djula:compile-template* &amp;quot;card-create.html&amp;quot;))
(defparameter +card-update.html+ (djula:compile-template* &amp;quot;card-edit.html&amp;quot;))
;; and so on.
&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
&lt;li&gt;let &lt;code&gt;asdf:make&lt;/code&gt; (and Deploy) save your binary. To try it, rename your &lt;code&gt;templates/&lt;/code&gt; directory to something else and run your app.&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;Addendum.&lt;/p&gt;

&lt;p&gt;An .asd system definition can reference static files, so they are part
of the build process and included into the delivered application. That&amp;rsquo;s
how you can ship a README file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  :components ((:static-file &amp;quot;README.md&amp;quot;)
               ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I did the same for my templates. To be honest, I don&amp;rsquo;t recall if there is a solid reason, since they are compiled and saved into the image anyhow with the compilation step above. I show this anyways, it looks like a good practice to me:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;            (:module &amp;quot;src/web/templates&amp;quot;
                        :components
                        ;; Order is important.
                        ((:static-file &amp;quot;login.html&amp;quot;)
                         (:static-file &amp;quot;404.html&amp;quot;)
                         (:static-file &amp;quot;base.html&amp;quot;)
                         (:static-file &amp;quot;dashboard.html&amp;quot;)
                         (:static-file &amp;quot;history.html&amp;quot;)
                         (:static-file &amp;quot;search.html&amp;quot;)
                         (:static-file &amp;quot;sell.html&amp;quot;)
                         ...))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;now we need to programmatically get the list of files from this &lt;code&gt;src/web/templates&lt;/code&gt; module and to compile everything:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((paths (djula:list-asdf-system-templates &amp;quot;bookshops&amp;quot; &amp;quot;src/web/templates&amp;quot;)))
  (loop for path in paths
     do (uiop:format! t &amp;quot;~&amp;amp;Compiling template file: ~a…~&amp;amp;&amp;quot; path)
       (djula:compile-template* path))
  (values t :all-done))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This snippet and the general instructions are documented: &lt;a href=&#34;https://mmontone.github.io/djula/djula/Deployment.html#Deployment&#34;&gt;https://mmontone.github.io/djula/djula/Deployment.html#Deployment&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to show how you do it.&lt;/p&gt;

&lt;p&gt;Bonus: here&amp;rsquo;s the &lt;code&gt;list-asdf-system-templates&lt;/code&gt; function. We use asdf functions to get a system name, its components, their names…&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun list-asdf-system-templates (asdf-system component)
  &amp;quot;List djula templates in ASDF-SYSTEM at COMPONENT.
  A list of template PATHNAMEs is returned.&amp;quot;
  (let* ((sys (asdf:find-system asdf-system))
         (children (asdf:component-children sys))
         (module (or (find component children :key #&#39;asdf:component-name :test #&#39;equal)
                     (error &amp;quot;Component ~S not found in system named ~S.~&amp;amp;Available components are: ~S&amp;quot; component asdf-system (mapcar #&#39;asdf:component-name children))))
         (alltemplates (remove-if-not (lambda (x) (typep x &#39;asdf:static-file))
                                      (asdf:module-components module))))
    (mapcar (lambda (it) (asdf:component-pathname it))
            alltemplates)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;serve-static-assets&#34;&gt;Serve static assets&lt;/h1&gt;

&lt;p&gt;At that point in time, I figured out static assets would need to be
worked on too. Hopefully, the people on Discord helped me and it was quickly solved.&lt;/p&gt;

&lt;p&gt;This is how I served static assets with Hunchentoot. We use a &amp;ldquo;folder dispatcher and handler&amp;rdquo;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://common-lisp-libraries.readthedocs.io/hunchentoot/#create-folder-dispatcher-and-handler&#34;&gt;https://common-lisp-libraries.readthedocs.io/hunchentoot/#create-folder-dispatcher-and-handler&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun serve-static-assets ()
  &amp;quot;Serve static assets under the /src/static/ directory when called with the /static/ URL root.&amp;quot;
  (push (hunchentoot:create-folder-dispatcher-and-handler
         &amp;quot;/static/&amp;quot; (merge-pathnames *default-static-directory*
                                     (asdf:system-source-directory :openbookstore) ;; =&amp;gt; NOT src/
                                     ))
        hunchentoot:*dispatch-table*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But when your app is on another machine… hence the need to ship the static assets into the standalone binary, and to ask Hunchentoot to serve them.&lt;/p&gt;

&lt;p&gt;What we do is pretty obvious: save our static files into a data structure, so this one is saved in the image, but we use a couple Lisp tricks so I comment the code below.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll see that this time I hardcoded the file names and I didn&amp;rsquo;t declare them on the .asd file… clearly there is room for improvement, be my guest.&lt;/p&gt;

&lt;p&gt;You can find &lt;a href=&#34;https://gitlab.com/myopenbookstore/openbookstore/-/blob/master/src/web/pre-web.lisp&#34;&gt;the file I use for my application here&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; pre-web.lisp
;;; Parameters and functions required before loading web.lisp
;;;
;;; We read the content of our static files and put them into variables, so that they can be saved in the Lisp image.
;;; We define %serve-static-file to simply return their content (as string),
;;; and because we use with the #. reader macro, we need to put these functions in another file than web.lisp.

;;; Where my static files are:
(defparameter *default-static-directory* &amp;quot;src/static/&amp;quot;
  &amp;quot;The directory where to serve static assets from (STRING). If it starts with a slash, it is an absolute directory. Otherwise, it will be a subdirectory of where the system :abstock is installed.
  Static assets are reachable under the /static/ prefix.&amp;quot;)

;;; We simply use a hash-table that maps a file name to its content, a a string.
;;; I love Serapeum&#39;s dict which is a readable hash-table, that&#39;s what I use:
(defparameter *static-files-content* (dict)
  &amp;quot;Content of our JS and CSS files.
  Hash-table with file name =&amp;gt; content (string).&amp;quot;)

;;; I read all my static files and I save them into the hash-table:
(defun %read-static-files-in-memory ()
  &amp;quot;Save the JS and CSS files in a variable in memory, so they can be saved at compile time.&amp;quot;
  (loop for file in (list &amp;quot;openbookstore.js&amp;quot;
                          &amp;quot;card-page.js&amp;quot;)
     with static-directory = (merge-pathnames *default-static-directory*
                                              (asdf:system-source-directory :bookshops))
     for content = (uiop:read-file-string (merge-pathnames file static-directory))
     do (setf (gethash file *static-files-content*) content)
     finally (return *static-files-content*)))

;; AT COMPILE TIME, read the content of our static files.
(%read-static-files-in-memory)

(defun %serve-static-file (path)
  &amp;quot;Return the content as a string of this static file.
  For standalone binaries delivery.&amp;quot;
  ;; &amp;quot;alert(&#39;yes, compiled in pre-web.lisp&#39;);&amp;quot;  ;; JS snippet to check if this dispatcher works.
  (gethash path *static-files-content*))  ;; this would not work without the #. reader macro.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is inside &amp;ldquo;web.lisp&amp;rdquo; that I set other rules for Hunchentoot. If it
recognizes my static files, we simply return their content, as a string.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t know if this works well with very big or with numerous files. But I-want-a-standalone-binary! For serious needs, I&amp;rsquo;d serve the static files with a proper server… I guess.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;#.&lt;/code&gt; reader macro to &lt;em&gt;get our files&amp;rsquo; content at compile time&lt;/em&gt;, this is why we needed to define our helper functions in another file, that is loaded before this one.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; web.lisp
(defun serve-static-assets-for-release ()
  &amp;quot;In a binary release, Hunchentoot can not serve files under the file system: we are on another machine and the files are not there.
  Hence we need to get the content of our static files into memory and give them to Hunchentoot.&amp;quot;
  (push
   (hunchentoot:create-regex-dispatcher &amp;quot;/static/openbookstore\.js&amp;quot;
                                        (lambda ()
                                          ;; Returning the result of the function calls silently fails. We need to return a string.
                                          ;; Here&#39;s the string, read at compile time.
                                          #.(%serve-static-file &amp;quot;openbookstore.js&amp;quot;)))
   hunchentoot:*dispatch-table*)

  (push
   (hunchentoot:create-regex-dispatcher &amp;quot;/static/card-page\.js&amp;quot;
                                        (lambda ()
                                          #.(%serve-static-file &amp;quot;card-page.js&amp;quot;)))
   hunchentoot:*dispatch-table*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, it is inside my &lt;code&gt;start-app&lt;/code&gt; function that I decide how to serve my static assets:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (hunchentoot:start *server*)
  (if (deploy:deployed-p)
      ;; Binary release: don&#39;t serve files by reading them from disk.
      (serve-static-assets-for-release)
      ;; Normal setup, running from sources: serve static files as usual.
      (serve-static-assets))
  (uiop:format! t &amp;quot;~&amp;amp;Application started on port ~a.~&amp;amp;&amp;quot; port)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Find my &lt;a href=&#34;https://gitlab.com/myopenbookstore/openbookstore/-/blob/master/src/web/web.lisp&#34;&gt;web.lisp file here&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;gitlab-ci&#34;&gt;Gitlab CI&lt;/h1&gt;

&lt;p&gt;I build my binary on Gitlab.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image: clfoundation/sbcl

# uncomment to run the jobs in parallel. They are now run one after the other.
# stages:
  # - test
  # - build

# We need to install some system dependencies,
# to clone libraries not in Quicklisp,
# and to update ASDF to &amp;gt;= 3.3.5 in order to use local-package-nicknames.
before_script:
  - apt-get update -qy
  - apt-get install -y git-core sqlite3 tar
  # The image doesn&#39;t have Quicklisp installed by default.
  - QUICKLISP_ADD_TO_INIT_FILE=true /usr/local/bin/install-quicklisp
  # clone libraries not in Quicklisp or if we need the latest version.
  - make install
  # Upgrade ASDF (UIOP) to 3.3.5 because we want package-local-nicknames.
  - mkdir -p ~/common-lisp/asdf/
  - ( cd ~/common-lisp/ &amp;amp;&amp;amp; wget https://asdf.common-lisp.dev/archives/asdf-3.3.5.tar.gz  &amp;amp;&amp;amp; tar -xvf asdf-3.3.5.tar.gz &amp;amp;&amp;amp; mv asdf-3.3.5 asdf )
  - echo &amp;quot;Content of ~/common-lisp/asdf/:&amp;quot; &amp;amp;&amp;amp; ls ~/common-lisp/asdf/

qa:
  allow_failure: true
  # stage: test
  script:
    # QA tools:
    # install Comby:
    - apt-get install -y sudo
    # - bash &amp;lt;(curl -sL get.comby.dev)
    - bash &amp;lt;(curl -sL https://raw.githubusercontent.com/vindarel/comby/set-release-1.0.0/scripts/install.sh)
    # install Colisper for simple lisp checks:
    - git clone https://github.com/vindarel/colisper ~/colisper
    - chmod +x ~/colisper/colisper.sh
    - cd src/ &amp;amp;&amp;amp; ~/colisper/colisper.sh

build:
  # stage: build
  script:
    - make build
  artifacts:
    name: &amp;quot;openbookstore&amp;quot;
    # Publish the bin/ directory (todo: rename, include version…)
    paths:
      - bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;closing-remarks&#34;&gt;Closing remarks&lt;/h1&gt;

&lt;p&gt;I am so excited by the possibilities this brings.&lt;/p&gt;

&lt;p&gt;I knew it was possible to do this in CL but I admit I thought it would be simpler… it turned out it is not a very crowded path. Now the steps are documented and google-able, here and everywhere else I could leave a comment, but it will be nice to come up with shorter and friendlier ready-to-use utilities. In a new web framework? And again, please share how you do all of this in the comments.&lt;/p&gt;

&lt;p&gt;Having this standalone binary dramatically simplifies my
deployment process. With a small web app, running from sources was
easy (once you set up Quicklisp, and ASDF, and…). But with a growing
application, that uses my local forks or code not yet pushed to
GitHub, deployment was becoming tedious, and it is now greatly
simplified. &lt;code&gt;rsync&lt;/code&gt;, &lt;code&gt;systemctl restart&lt;/code&gt; and done.&lt;/p&gt;

&lt;p&gt;Its only limitation is that you need the same libc version on the
target OS as on your local machine. So, back in august I
could build on my machine and send the result to my VPS, but I upgraded my
Debian-ish system, and left the server with its (very) old Ubuntu version, so
I can&amp;rsquo;t run the binary from my machine there any more… I must resort to
a CI pipeline that uses a matrix of Ubuntu versions, or build with Docker
or a virtual machine. Or run from sources… Maybe soon I will build &lt;a href=&#34;https://www.timmons.dev/posts/static-executables-with-sbcl.html&#34;&gt;(truly) static executables: they are coming to SBCL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I repeat again the good side: my friends (on Debian so far) can download the app, run &lt;code&gt;bin/openbookstore&lt;/code&gt; and it works \o/&lt;/p&gt;

&lt;p&gt;One last thing I&amp;rsquo;d like to do is to be able to double-click an executable to start the app, and to have one single file (and not an archive that extracts as a directory, although it is not too bad!). This looks possible with &lt;a href=&#34;https://makeself.io/&#34;&gt;Makeself&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to try the standalone binary on your GNU/Linux system (does it actually work on other distros?), download the artifacts of the latest passing build on the &lt;a href=&#34;https://gitlab.com/myopenbookstore/openbookstore/-/pipelines&#34;&gt;pipelines page&lt;/a&gt;, or grab it &lt;a href=&#34;https://gitlab.com/myopenbookstore/openbookstore/-/jobs/artifacts/master/download?job=build&#34;&gt;with this direct link&lt;/a&gt;. Un-zip, run &lt;code&gt;bin/bookshops&lt;/code&gt; and go to localhost address shown in the output (and also create an admin user as shown in the readme). You can leave me a comment here, &lt;a href=&#34;https://gitter.im/openbookstore-developers/community&#34;&gt;on Gitter&lt;/a&gt;, on Discord or with a good ol&amp;rsquo; email.&lt;/p&gt;

&lt;p&gt;Stay tuned, &lt;a href=&#34;https://github.com/OpenBookStore/openbookstore&#34;&gt;OpenBookStore&lt;/a&gt; is still a work in progress but it will be a Common Lisp application flagship ;)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lisp for the web: deploying with Systemd, gotchas and solutions</title>
      <link>/blog/lisp-for-the-web-deploy-with-systemd/</link>
      <pubDate>Tue, 30 Aug 2022 16:57:37 +0200</pubDate>
      
      <guid>/blog/lisp-for-the-web-deploy-with-systemd/</guid>
      <description>

&lt;p&gt;How do you run your Common Lisp (web) application on your server?
Nowadays most GNU/Linux distros have Systemd. I recently used it more,
with a mix of applications running from source, from a binary, running
locally or on my VPS. I had to bypass a few gotchas, so let&amp;rsquo;s
recap&amp;rsquo; what you need to know.&lt;/p&gt;

&lt;p&gt;Also &lt;em&gt;stay tuned&lt;/em&gt;: next, we&amp;rsquo;ll see how to build a standalone binary
for your Common Lisp application with Deploy (so that we handle
foreign libraries like libssl), how to include your Djula HTML
templates as well as your static assets. This, in turns, makes it
straightforward to &lt;em&gt;ship your web app into an Electron desktop
window&lt;/em&gt;.&lt;/p&gt;



&lt;div class=&#34;info&#34; style=&#34;background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px;&#34;&gt;
&lt;strong&gt;INFO:&lt;/strong&gt;
dear readers, here&#39;s &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISP-JOURNEY-220915&#34;&gt; the best price I can set for my Udemy course &#34;Learn Lisp effectively&#34; &lt;/a&gt;, it will be available for 5 days! Thanks all for your support (NB: I&#39;m working on the chapter on condition handling and new chapters are available for existing students).
&lt;/div&gt;



&lt;h2 id=&#34;before-systemd&#34;&gt;Before Systemd&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s say we can run our app like this: we load the system definition,
its dependencies, and we call the entry point.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sbcl --load my-app.asd \
     --eval &#39;(ql:quickload :my-app)&#39; \
     --eval &#39;(my-app:start-app)&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we need to put the app on the background, we must ensure that if
it fails, it is restarted, if the server is restarted, our app too, we
must ensure we get to see the logs, etc.&lt;/p&gt;

&lt;p&gt;Maybe you run your app inside of Emacs on your VPS… maybe you run your
app inside &lt;code&gt;tmux&lt;/code&gt;. This works and it is convenient to get back to the
Lisp REPL, but this doesn&amp;rsquo;t ensure a restart on failure.&lt;/p&gt;

&lt;h2 id=&#34;systemd-daemonizing-restarting-in-case-of-crashes-handling-logs&#34;&gt;Systemd: daemonizing, restarting in case of crashes, handling logs&lt;/h2&gt;

&lt;p&gt;Systemd (or the service system of your distro) can help with all that.&lt;/p&gt;

&lt;p&gt;Write a service file like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ emacs -nw /etc/systemd/system/my-app.service
[Unit]
Description=Lisp app example

[Service]
WorkingDirectory=/path/to/your/app
# Next, your command, with the full path to SBCL.
# This works, locally. Be sure to see the last section.
ExecStart=/usr/bin/sbcl --load run.lisp
# or: use a path to your binary.
Type=simple
Restart=always
RestartSec=10
# Use environment variables:
Environment=&amp;quot;SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN&amp;quot;

# Start or restart at boot:
[Install]
WantedBy=basic.target
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you run your app on the terminal, ensure that its webserver
(Hunchentoot here) stays listening correctly on the foreground
(otherwise see below):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sbcl --load run.lisp
Hunchentoot server is started.
Listening on localhost:9003.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now run this command to &lt;strong&gt;start the service&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo systemctl start my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to check its &lt;strong&gt;status&lt;/strong&gt; use this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;systemctl status my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Systemd handles &lt;strong&gt;logs&lt;/strong&gt; for you. We make our app write to stdout or stderr, Systemd writes logs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;journalctl -u my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;use &lt;code&gt;-f -n 30&lt;/code&gt; to see live updates of logs, where &lt;code&gt;-n&lt;/code&gt; is the number of lines you want as context.&lt;/p&gt;

&lt;p&gt;The following tells Systemd to handle crashes and to &lt;strong&gt;restart the app&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Restart=always
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and this makes it &lt;strong&gt;start the app after a reboot&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Install]
WantedBy=basic.target
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to enable it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo systemctl enable my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now keep in mind a couple things.&lt;/p&gt;

&lt;h3 id=&#34;make-it-stay-on-the-foreground&#34;&gt;Make it stay on the foreground&lt;/h3&gt;

&lt;p&gt;The first gotcha is that your app must stay on the foreground.&lt;/p&gt;

&lt;p&gt;If you run your app from source, you might have nothing to do, you&amp;rsquo;ll
get a Lisp REPL, from which you can interact with your running
application. Awesome.&lt;/p&gt;

&lt;p&gt;But, if you build a binary, you might see this error when you run it
with Systemd:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-txt&#34;&gt;* ;
; compilation unit aborted
; caught 1 fatal error condition&amp;quot; error.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This puzzled me: I thought I had a Lisp prompt (the &lt;code&gt;* ;&lt;/code&gt;) and
that my program crashed, but no. I knew it, that&amp;rsquo;s simply Lisp quitting
too early. Don&amp;rsquo;t rush and double check that your binary runs
correctly.&lt;/p&gt;

&lt;p&gt;What you must do can be found elsewhere (the Cookbook!): in your main
function where you start your app, in this example with Hunchentoot,
put its thread in the foreground:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; with bordeaux-threads. Also sb-ext: join-thread, thread-name, list-all-threads.
(bt:join-thread (find-if (lambda (th)
                            (search &amp;quot;hunchentoot&amp;quot; (bt:thread-name th)))
                          (bt:all-threads)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;let-it-crash-disable-debugger&#34;&gt;Let it crash: &lt;code&gt;--disable-debugger&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;We want our app to crash so that it can be re-started automatically:
you’ll want the &lt;code&gt;--disable-debugger&lt;/code&gt; flag with SBCL, when you run your
app from sources.&lt;/p&gt;

&lt;h3 id=&#34;relying-on-quicklisp&#34;&gt;Relying on Quicklisp&lt;/h3&gt;

&lt;p&gt;When you run your apps locally, you most probably rely on Quicklisp
being installed and being started in your init file (&lt;code&gt;~/.sbclrc&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames &amp;quot;quicklisp/setup.lisp&amp;quot;
                                       (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are 2 gotchas.&lt;/p&gt;

&lt;p&gt;Systemd will, by default, run your app as root, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if it happened you did install Quicklisp on your production machine,
you probably didn&amp;rsquo;t install it as root, so Systemd won&amp;rsquo;t find the
init file that initializes Quicklisp (and so your startup scripts
will fail).

&lt;ul&gt;
&lt;li&gt;you can use SBCL&amp;rsquo;s &lt;code&gt;--userinit&lt;/code&gt; flag to tell the username where to find the init file.&lt;/li&gt;
&lt;li&gt;you can set the Systemd user with &lt;code&gt;User=xyz&lt;/code&gt; in the &lt;code&gt;[service]&lt;/code&gt; section (disclaimer: untested).&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;the Quicklisp snippet will fail at &lt;code&gt;(user-homedir-pathname)&lt;/code&gt;, for a clash on usernames too, so Quicklisp won&amp;rsquo;t find its &lt;code&gt;setup.lisp&lt;/code&gt; file. I replaced this function call with a hard path (&lt;code&gt;/home/vindarel/&lt;/code&gt;), until I used a standalone binary.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;That&amp;rsquo;s it. Now you can deploy in peace. I hope I saved you some hours. Now these issues are better google-able \o/&lt;/p&gt;

&lt;p&gt;See you around and stay tuned.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>State of Common Lisp Web Development - an overview</title>
      <link>/web-dev/</link>
      <pubDate>Fri, 24 Jun 2022 07:51:49 +0100</pubDate>
      
      <guid>/web-dev/</guid>
      <description>

&lt;p&gt;Caution [from 2017: what a road since then]: this is a draft. I take notes and write more in other resources (the Cookbook, my blog).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;update, Jan 2025&lt;/strong&gt;: I published a new resources specialized in web development in Common Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://web-apps-in-lisp.github.io/&#34;&gt;https://web-apps-in-lisp.github.io/&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;update, January 2024&lt;/strong&gt;: see my new video on Youtube, a demo on how to assemble Hunchentoot, easy-routes, Djula templates (with ready-to-use Bulma themes), with error handling and common traps: &lt;a href=&#34;https://www.youtube.com/watch?v=h_noB1sI_e8&#34;&gt;https://www.youtube.com/watch?v=h_noB1sI_e8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;update, June 2022&lt;/em&gt;: see my web project skeleton, it illustrates and fixes common issues: &lt;a href=&#34;https://github.com/vindarel/cl-cookieweb&#34;&gt;https://github.com/vindarel/cl-cookieweb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;update july, 5th 2019&lt;/em&gt;: I put this content into the Cookbook: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/web.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/web.html&lt;/a&gt;, fixing a long-standing request.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;new post&lt;/em&gt;: why and how to live-reload one&amp;rsquo;s running web application: &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/&#34;&gt;https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;new project skeleton&lt;/em&gt;: &lt;a href=&#34;https://github.com/vindarel/lisp-web-template-productlist&#34;&gt;lisp-web-template-productlist&lt;/a&gt;: Hunchentoot + easy-routes + Djula templates + Bulma CSS + a Makefile to build the project&lt;/p&gt;

&lt;p&gt;See also the
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#network-and-internet&#34;&gt;Awesome CL list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Information is at the moment scarce and spread appart, Lisp web
frameworks and libraries evolve and take different approaches.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d like to know what&amp;rsquo;s possible, what&amp;rsquo;s lacking, see how to
quickstart everything, see code snippets and, most of all, see how to
do things that I couldn&amp;rsquo;t do before such as hot reloading, building
self-contained executables, shipping a multiplatform web app.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Prior notice:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some people sell ten pages long ebooks or publish their tutorial on
Gitbook to have a purchase option. I prefer to enhance the
collaborative Cookbook (I am by far &lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/graphs/contributors&#34;&gt;the main
contributor&lt;/a&gt;). You
can tip me on Kofi if you like: &lt;a href=&#34;https://ko-fi.com/vindarel&#34;&gt;https://ko-fi.com/vindarel&lt;/a&gt; Thanks !&lt;/p&gt;

&lt;script type=&#39;text/javascript&#39; src=&#39;https://storage.ko-fi.com/cdn/widget/Widget_2.js&#39;&gt;&lt;/script&gt;&lt;script type=&#39;text/javascript&#39;&gt;kofiwidget2.init(&#39;&#39;, &#39;#29abe0&#39;, &#39;K3K828W0V&#39;);kofiwidget2.draw();&lt;/script&gt;

&lt;hr /&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#web-application-environments&#34;&gt;Web application environments&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#clack-lack&#34;&gt;Clack, Lack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#web-frameworks&#34;&gt;Web frameworks&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hunchentoot&#34;&gt;Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#caveman&#34;&gt;Caveman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#snooze&#34;&gt;Snooze&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#radiance&#34;&gt;Radiance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cl-rest-server&#34;&gt;cl-rest-server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#wookie&#34;&gt;Wookie&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#weblocks-solving-the-javascript-problem&#34;&gt;Weblocks (solving the Javascript problem)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tasks&#34;&gt;Tasks&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#accessing-url-parameters&#34;&gt;Accessing url parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#session-an-cookies&#34;&gt;Session an cookies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#data-storage&#34;&gt;Data storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sql&#34;&gt;SQL&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#persistent-datastores&#34;&gt;Persistent datastores&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#migrations&#34;&gt;Migrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#forms&#34;&gt;Forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#debugging&#34;&gt;Debugging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#testing&#34;&gt;Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#misc&#34;&gt;Misc&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#oauth-job-queues-etc&#34;&gt;Oauth, Job queues, etc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#templating-engines&#34;&gt;Templating engines&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#html-based&#34;&gt;HTML-based&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#lisp-based&#34;&gt;Lisp-based&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#javascript&#34;&gt;Javascript&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#parenscript&#34;&gt;Parenscript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#jscl&#34;&gt;JSCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ajax&#34;&gt;Ajax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-case-webblocks---reblocks-2017&#34;&gt;The case Webblocks - Reblocks, 2017&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#shipping&#34;&gt;Shipping&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#building&#34;&gt;Building&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#multiplatform-delivery-with-electron-ceramic&#34;&gt;Multiplatform delivery with Electron (Ceramic)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deployment&#34;&gt;Deployment&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#manually&#34;&gt;Manually&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-clackhttpquickdocsorgclack&#34;&gt;with &lt;a href=&#34;http://quickdocs.org/clack/&#34;&gt;Clack&lt;/a&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-docker&#34;&gt;with Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#on-heroku&#34;&gt;On Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#systemd-daemonizing-restarting-in-case-of-crashes-handling-logs&#34;&gt;Systemd: daemonizing, restarting in case of crashes, handling logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#debugging-sbcl-error-ensurespace-failed-to-allocate-n-bytes&#34;&gt;Debugging SBCL error: ensure_space: failed to allocate n bytes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#connecting-to-a-remote-swank-server&#34;&gt;Connecting to a remote Swank server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hot-reload&#34;&gt;Hot reload&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;web-application-environments&#34;&gt;Web application environments&lt;/h1&gt;

&lt;h2 id=&#34;clack-lack&#34;&gt;Clack, Lack&lt;/h2&gt;

&lt;p&gt;Clack is to Lisp what WSGI is to Python. However it is mostly undocumented and not as battle-proofed as Hunchentoot.&lt;/p&gt;

&lt;h1 id=&#34;web-frameworks&#34;&gt;Web frameworks&lt;/h1&gt;

&lt;h2 id=&#34;hunchentoot&#34;&gt;Hunchentoot&lt;/h2&gt;

&lt;p&gt;The de-facto web server, with the best documentation (cough looking old cough),
the most websites on production. Lower level than a web framework
(defining routes seems weird at first). I think worth knowing.&lt;/p&gt;

&lt;p&gt;Its terminology is different from what we are used to (&amp;ldquo;routes&amp;rdquo; are
not called routes but we create handlers), part I don&amp;rsquo;t know why and
part because the Lisp image-based development allows for more, and
thus needs more terminology. For example, we can run two applications
on different URLs on the same image.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://edicl.github.io/hunchentoot/&#34;&gt;https://edicl.github.io/hunchentoot/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;edit&lt;/strong&gt;: here&amp;rsquo;s a modern looking page: &lt;a href=&#34;https://digikar99.github.io/common-lisp.readthedocs/hunchentoot/&#34;&gt;https://digikar99.github.io/common-lisp.readthedocs/hunchentoot/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;caveman&#34;&gt;Caveman&lt;/h2&gt;

&lt;p&gt;A popular web framework, or so it seems by the github stars, written by a super-productive lisper, with nice documentation for basic
stuff but lacking for the rest, based on Clack (webserver interface,
think Python&amp;rsquo;s WSGI), uses Hunchentoot by default.&lt;/p&gt;

&lt;p&gt;I feel like basic functions are too cumbersome (accessing url parameters).&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/caveman&#34;&gt;https://github.com/fukamachi/caveman&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;snooze&#34;&gt;Snooze&lt;/h2&gt;

&lt;p&gt;By the maintainer of Sly, Emacs&amp;rsquo; Yasnippet,…&lt;/p&gt;

&lt;p&gt;Defining routes is like defining functions. Built-in features that are
available as extensions in Clack-based frameworks (setting to get a
stacktrace on the browser, to fire up the debugger or to return a
404,…). Definitely worth exploring.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/joaotavora/snooze&#34;&gt;https://github.com/joaotavora/snooze&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;radiance&#34;&gt;Radiance&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Shirakumo/radiance&#34;&gt;Radiance&lt;/a&gt;, with extensive tutorial and existing apps.&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t look like a web framework to me. It has ready-to-use components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;admin page (but what does it do?)&lt;/li&gt;
&lt;li&gt;auth system&lt;/li&gt;
&lt;li&gt;user: provide user accounts and permissions&lt;/li&gt;
&lt;li&gt;image hosting&lt;/li&gt;
&lt;li&gt;there is an email marketing system in development…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;cl-rest-server&#34;&gt;cl-rest-server&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/mmontone/cl-rest-server&#34;&gt;cl-rest-server&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a library for writing REST Web APIs in Common Lisp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Features: validation via schemas, Swagger support, authentication, logging, caching, permission checking…&lt;/p&gt;

&lt;p&gt;It seems complete, it is maintained, the author seems to be doing web development in CL for a living. Note to self: I want to interview him.&lt;/p&gt;

&lt;h2 id=&#34;wookie&#34;&gt;Wookie&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/orthecreedence/wookie&#34;&gt;https://github.com/orthecreedence/wookie&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An asynchronous web server, by an impressive lisper, who built many async
libraries. Used for the &lt;a href=&#34;https://github.com/turtl/api/&#34;&gt;Turtl&lt;/a&gt; api
backend. Dealing with async brings its own set of problems (how will
be debugging ?).&lt;/p&gt;

&lt;p&gt;Nice api to build routes, good documentation: &lt;a href=&#34;http://wookie.lyonbros.com/&#34;&gt;http://wookie.lyonbros.com/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;weblocks-solving-the-javascript-problem&#34;&gt;Weblocks (solving the Javascript problem)&lt;/h2&gt;

&lt;p&gt;Weblocks allows to create dynamic pages without a line of JavaScript,
all in Lisp. It was started years ago and it saw a large update and
refactoring lately.&lt;/p&gt;

&lt;p&gt;It isn&amp;rsquo;t the easy path to web development in CL but there&amp;rsquo;s great potential IMO.&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t do double data binding as in modern JS frameworks. But new projects are being developed…&lt;/p&gt;

&lt;p&gt;See our presentation below.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://40ants.com/weblocks/quickstart.html&#34;&gt;http://40ants.com/weblocks/quickstart.html&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;tasks&#34;&gt;Tasks&lt;/h1&gt;

&lt;h2 id=&#34;accessing-url-parameters&#34;&gt;Accessing url parameters&lt;/h2&gt;

&lt;p&gt;It is easy and well explained with Hunchentoot or &lt;code&gt;easy-routes&lt;/code&gt; in the Cookbook.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://borretti.me/lucerne/docs/overview.html&#34;&gt;Lucerne&lt;/a&gt; has a nice
&lt;code&gt;with-params&lt;/code&gt; macro that makes accessing post or url query parameters a breeze:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;@route app (:post &amp;quot;/tweet&amp;quot;)
(defview tweet ()
  (if (lucerne-auth:logged-in-p)
      (let ((user (current-user)))
        (with-params (tweet)
          (utweet.models:tweet user tweet))
        (redirect &amp;quot;/&amp;quot;))
      (render-template (+index+)
                       :error &amp;quot;You are not logged in.&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/joaotavora/snooze&#34;&gt;Snooze&lt;/a&gt;&amp;rsquo;s way is simple and
lispy: we define routes like methods and parameters as keys:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute lispdoc (:get :text/* name &amp;amp;key (package :cl) (doctype &#39;function))
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;matches &lt;code&gt;/lispdoc&lt;/code&gt;, &lt;code&gt;/lispdoc/foo&lt;/code&gt; and &lt;code&gt;/lispdoc/foo?package=arg&lt;/code&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;On the contrary, I find Caveman&amp;rsquo;s and Ningle&amp;rsquo;s ways cumbersome.&lt;/p&gt;

&lt;p&gt;Ningle:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (ningle:route *app* &amp;quot;/hello/:name&amp;quot;)
      #&#39;(lambda (params)
          (format nil &amp;quot;Hello, ~A&amp;quot; (cdr (assoc &amp;quot;name&amp;quot; params :test #&#39;string=)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;The above controller will be invoked when you access to &amp;ldquo;/hello/Eitaro&amp;rdquo; or &amp;ldquo;/hello/Tomohiro&amp;rdquo;, and then (cdr (assoc &amp;ldquo;name&amp;rdquo; params :test #&amp;lsquo;string=)) will be &amp;ldquo;Eitaro&amp;rdquo; and &amp;ldquo;Tomohiro&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and it doesn&amp;rsquo;t say about query parameters. I had to &lt;a href=&#34;https://stackoverflow.com/questions/43778570/how-to-get-url-query-parameters-in-clack-lucerne-or-caveman&#34;&gt;ask&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(assoc &amp;quot;the-query-param&amp;quot; (clack.request:query-parameter lucerne:*request*) :test &#39;string=)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Caveman:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Parameter keys contain square brackets (&amp;rdquo;[&amp;rdquo; &amp;amp; &amp;ldquo;]&amp;rdquo;) will be parsed as structured parameters. You can access the parsed parameters as _parsed in routers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute &amp;quot;/edit&amp;quot; (&amp;amp;key _parsed)
  (format nil &amp;quot;~S&amp;quot; (cdr (assoc &amp;quot;person&amp;quot; _parsed :test #&#39;string=))))
;=&amp;gt; &amp;quot;((\&amp;quot;name\&amp;quot; . \&amp;quot;Eitaro\&amp;quot;) (\&amp;quot;email\&amp;quot; . \&amp;quot;e.arrows@gmail.com\&amp;quot;) (\&amp;quot;birth\&amp;quot; . ((\&amp;quot;year\&amp;quot; . 2000) (\&amp;quot;month\&amp;quot; . 1) (\&amp;quot;day\&amp;quot; . 1))))&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;session-an-cookies&#34;&gt;Session an cookies&lt;/h2&gt;

&lt;h2 id=&#34;data-storage&#34;&gt;Data storage&lt;/h2&gt;

&lt;h2 id=&#34;sql&#34;&gt;SQL&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/mito&#34;&gt;Mito&lt;/a&gt; works for MySQL, Postgres
and SQLite3 on SBCL and CCL.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/databases.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can define models with a regular class which has a &lt;code&gt;mito:dao-table-class&lt;/code&gt; &lt;code&gt;:metaclass&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create the table with &lt;code&gt;ensure-table-exists&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ensure-table-exists &#39;user)
;-&amp;gt; ;; CREATE TABLE IF NOT EXISTS &amp;quot;user&amp;quot; (
;       &amp;quot;id&amp;quot; BIGSERIAL NOT NULL PRIMARY KEY,
;       &amp;quot;name&amp;quot; VARCHAR(64) NOT NULL,
;       &amp;quot;email&amp;quot; VARCHAR(128),
;       &amp;quot;created_at&amp;quot; TIMESTAMP,
;       &amp;quot;updated_at&amp;quot; TIMESTAMP
;   ) () [0 rows] | MITO.DAO:ENSURE-TABLE-EXISTS
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;persistent-datastores&#34;&gt;Persistent datastores&lt;/h3&gt;

&lt;h3 id=&#34;migrations&#34;&gt;Migrations&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/mito&#34;&gt;Mito&lt;/a&gt; has migrations support and
DB schema versioning for MySQL, Postgres and SQLite3, on SBCL and
CCL. Once we have changed our model definition, we have commands to
see the generated SQL and to apply the migration.&lt;/p&gt;

&lt;p&gt;We inspect the SQL: (suppose we just added the email field into the &lt;code&gt;user&lt;/code&gt; class above)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:migration-expressions &#39;user)
;=&amp;gt; (#&amp;lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&amp;gt;
;    #&amp;lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we can apply the migration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:migrate-table &#39;user)
;-&amp;gt; ;; ALTER TABLE &amp;quot;user&amp;quot; ALTER COLUMN &amp;quot;email&amp;quot; TYPE character varying(128), ALTER COLUMN &amp;quot;email&amp;quot; SET NOT NULL () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;   ;; CREATE UNIQUE INDEX &amp;quot;unique_user_email&amp;quot; ON &amp;quot;user&amp;quot; (&amp;quot;email&amp;quot;) () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;-&amp;gt; (#&amp;lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&amp;gt;
;    #&amp;lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/eudoxia0/crane&#34;&gt;Crane&lt;/a&gt; advertises &lt;strong&gt;automatic&lt;/strong&gt;
migrations, i.e. it would run them after a &lt;code&gt;C-c C-c&lt;/code&gt;. Unfortunately Crane has
some issues, it doesn&amp;rsquo;t work with sqlite yet and the author is busy
elsewhere. It didn&amp;rsquo;t work for me at first try.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s hope the author comes back to work on this in a near future.&lt;/p&gt;

&lt;h2 id=&#34;forms&#34;&gt;Forms&lt;/h2&gt;

&lt;p&gt;There are a few libraries, see the awesome-cl list. At least one is well active.&lt;/p&gt;

&lt;h2 id=&#34;debugging&#34;&gt;Debugging&lt;/h2&gt;

&lt;p&gt;On an error we are usually dropped into the interactive debugger by default.&lt;/p&gt;

&lt;p&gt;Snooze gives options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the debugger,&lt;/li&gt;
&lt;li&gt;print the stacktrace in the browser (like clack-errors below, but built-in),&lt;/li&gt;
&lt;li&gt;display a custom 404.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/eudoxia0/clack-errors&#34;&gt;clack-errors&lt;/a&gt;. Like a Flask
or Django stacktrace in the browser. For Caveman, Ningle and family.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By default, when Clack throws an exception when rendering a page, the server waits for the response until it times out while the exception waits in the REPL. This isn&amp;rsquo;t very useful. So now there&amp;rsquo;s this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It prints the stacktrace along with some request details on the
browser. Can return a custom error page in production.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://camo.githubusercontent.com/17dd6e0a7a916c8118f0134a94404f6757bee9dc/68747470733a2f2f7261772e6769746875622e636f6d2f6575646f786961302f636c61636b2d6572726f72732f6d61737465722f73637265656e73686f742d6465762e706e67&#34; width=&#34;800px&#34;&gt;&lt;/img&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/BnMcGn/clack-pretend&#34;&gt;clack-pretend&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are you tired of jumping to your web browser every time you need to test your work in Clack? Clack-pretend will capture and replay calls to your clack middleware stack. When developing a web application with clack, you will often find it inconvenient to run your code from the lisp REPL because it expects a clack environment, including perhaps, cookies or a logged-in user. With clack-pretend, you can run prior web requests from your REPL, moving development back where it belongs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;testing&#34;&gt;Testing&lt;/h2&gt;

&lt;p&gt;Testing with a local DB: example of a &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html#testing&#34;&gt;testing macro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We would use &lt;a href=&#34;https://github.com/fukamachi/envy&#34;&gt;envy&lt;/a&gt; to switch configurations.&lt;/p&gt;

&lt;h2 id=&#34;misc&#34;&gt;Misc&lt;/h2&gt;

&lt;h3 id=&#34;oauth-job-queues-etc&#34;&gt;Oauth, Job queues, etc&lt;/h3&gt;

&lt;h1 id=&#34;templating-engines&#34;&gt;Templating engines&lt;/h1&gt;

&lt;h2 id=&#34;html-based&#34;&gt;HTML-based&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://mmontone.github.io/djula/&#34;&gt;Djula&lt;/a&gt;&lt;/strong&gt;: as Django
templates. Good documentation. Comes by default in Lucerne and Caveman.&lt;/p&gt;

&lt;p&gt;We also use a dot to access attributes of dict-like variables (plists,
alists, hash-tables, arrays and CLOS objects), such a feature being
backed by the &lt;a href=&#34;https://github.com/AccelerationNet/access&#34;&gt;access&lt;/a&gt;
library.&lt;/p&gt;

&lt;p&gt;We wanted once to use structs and didn&amp;rsquo;t find how to it directly in
Djula, so we resorted in a quick helper function to transform the
struct in an alist.&lt;/p&gt;

&lt;p&gt;Defining custom template filters is straightforward in Djula, really a
breeze compared to Django.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/eudoxia0/eco&#34;&gt;Eco&lt;/a&gt;&lt;/strong&gt; - a mix of html with lisp expressions.&lt;/p&gt;

&lt;p&gt;Truncated example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;body&amp;gt;
      &amp;lt;% if posts %&amp;gt;
        &amp;lt;h1&amp;gt;Recent Posts&amp;lt;/h1&amp;gt;
        &amp;lt;ul id=&amp;quot;post-list&amp;quot;&amp;gt;
          &amp;lt;% loop for (title . snippet) in posts %&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;%= title %&amp;gt; - &amp;lt;%= snippet %&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;% end %&amp;gt;
        &amp;lt;/ul&amp;gt;
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;lisp-based&#34;&gt;Lisp-based&lt;/h2&gt;

&lt;p&gt;I prefer the semantics of
&lt;a href=&#34;https://github.com/ruricolist/spinneret&#34;&gt;Spinneret&lt;/a&gt; over cl-who. It
also has more features (like embeddable markdown, warns on malformed html, and more).&lt;/p&gt;

&lt;h1 id=&#34;javascript&#34;&gt;Javascript&lt;/h1&gt;

&lt;h2 id=&#34;parenscript&#34;&gt;Parenscript&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Parenscript is a translator from an extended subset of Common Lisp to JavaScript. Parenscript code can run almost identically on both the browser (as JavaScript) and server (as Common Lisp).
Parenscript code is treated the same way as Common Lisp code, making the full power of Lisp macros available for JavaScript. This provides a web development environment that is unmatched in its ability to reduce code duplication and provide advanced meta-programming facilities to web developers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://common-lisp.net/project/parenscript/&#34;&gt;https://common-lisp.net/project/parenscript/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;jscl&#34;&gt;JSCL&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Lisp-to-Javascript compiler bootstrapped from Common Lisp and executed from the browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/jscl-project/jscl&#34;&gt;https://github.com/jscl-project/jscl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://t-cool.github.io/jscl-playground/&#34;&gt;https://t-cool.github.io/jscl-playground/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;ajax&#34;&gt;Ajax&lt;/h2&gt;

&lt;p&gt;Is it possible to write Ajax-based pages only in CL?&lt;/p&gt;

&lt;h2 id=&#34;the-case-webblocks-reblocks-2017&#34;&gt;The case Webblocks - Reblocks, 2017&lt;/h2&gt;

&lt;p&gt;Weblocks is an &amp;ldquo;isomorphic&amp;rdquo; web frameworks that solves the &amp;ldquo;Javascript
problem&amp;rdquo;. It allows to write the backend and an interactive client
interface in Lisp, without a line of Javascript, in our usual Lisp
development environment.&lt;/p&gt;

&lt;p&gt;The framework evolves around widgets, that are updated server-side
and are automatically redisplayed with transparent ajax calls on the
client.&lt;/p&gt;

&lt;p&gt;It is being massively refactored, simplified, rewritten and documented
since 2017. See the new quickstart:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://40ants.com/weblocks/quickstart.html&#34;&gt;http://40ants.com/weblocks/quickstart.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Writing a dynamic todo-app resolves in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defining a widget class for a task:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defwidget task ()
        ((title
          :initarg :title
          :accessor title)
         (done
          :initarg :done
          :initform nil
          :accessor done)))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;doing the same for a list of tasks:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defwidget task-list ()
        ((tasks
          :initarg :tasks
          :accessor tasks)))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;saying how to render these widgets in html by extending the &lt;code&gt;render&lt;/code&gt; method:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod render ((task task))
        &amp;quot;Render a task.&amp;quot;
        (with-html
              (:span (if (done task)
                         (with-html
                               (:s (title task)))
                       (title task)))))

(defmethod render ((widget task-list))
        &amp;quot;Render a list of tasks.&amp;quot;
        (with-html
              (:h1 &amp;quot;Tasks&amp;quot;)
              (:ul
                (loop for task in (tasks widget) do
                      (:li (render task))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;telling how to initialize the Weblocks app:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod weblocks/session:init ((app tasks))
         (declare (ignorable app))
         (let ((tasks (make-task-list &amp;quot;Make my first Weblocks app&amp;quot;
                                      &amp;quot;Deploy it somewhere&amp;quot;
                                      &amp;quot;Have a profit&amp;quot;)))
           (make-instance &#39;task-list :tasks tasks)))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;and then writing functions to interact with the widgets, for example adding a task:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod add-task ((task-list task-list) title)
        (push (make-task title)
              (tasks task-list))
        (update task-list))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Adding an html form and calling the new &lt;code&gt;add-task&lt;/code&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod render ((task-list task-list))
        (with-html
          (:h1 &amp;quot;Tasks&amp;quot;)
          (loop for task in (tasks task-list) do
            (render task))
          (with-html-form (:POST (lambda (&amp;amp;key title &amp;amp;allow-other-keys)
                                         (add-task task-list title)))
            (:input :type &amp;quot;text&amp;quot;
                    :name &amp;quot;title&amp;quot;
                    :placeholder &amp;quot;Task&#39;s title&amp;quot;)
            (:input :type &amp;quot;submit&amp;quot;
                    :value &amp;quot;Add&amp;quot;))))
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;shipping&#34;&gt;Shipping&lt;/h1&gt;

&lt;p&gt;We can build our web app from sources, no worries, that works.&lt;/p&gt;

&lt;h2 id=&#34;building&#34;&gt;Building&lt;/h2&gt;

&lt;p&gt;We can build an executable also for web apps. That simplifies a
deployment process drastically.&lt;/p&gt;

&lt;p&gt;We can even get a Lisp REPL and interact with the running web app, in
which we can even install new Quicklisp dependencies. That&amp;rsquo;s quite
incredible, and it&amp;rsquo;s very useful, if not to hot-reload a web app
(which I do anyways but that might be risky), at least to reload a user&amp;rsquo;s
configuration file.&lt;/p&gt;

&lt;p&gt;This is the general way:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(sb-ext:save-lisp-and-die #p&amp;quot;name-of-executable&amp;quot; :toplevel #&#39;main :executable t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But this is an SBCL-specific command, so we can be generic and use
&lt;code&gt;asdf:make&lt;/code&gt;, with a couple lines inside our system .asd
declaration. See the Cookbook:
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html#with-asdf&#34;&gt;https://lispcookbook.github.io/cl-cookbook/scripting.html#with-asdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if you run your binary, your app will start up all fine, but it
will quit instantly. We need to put the web server thread on the
foreground:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun main ()
    ;; with bordeaux-threads. Also sb-ext: join-thread, thread-name, list-all-threads.
    (bt:join-thread (find-if (lambda (th)
                                (search &amp;quot;hunchentoot&amp;quot; (bt:thread-name th)))
                              (bt:all-threads))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When I run it, Hunchentoot stays listening at the foreground:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./my-webapp
Hunchentoot server is started.
Listening on localhost:9003.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I can use a &lt;code&gt;tmux&lt;/code&gt; session (&lt;code&gt;tmux&lt;/code&gt;, then &lt;code&gt;C-b d&lt;/code&gt; to detach it) or better yet, start the app with Systemd, see below.&lt;/p&gt;

&lt;p&gt;But we need something more for real apps, we need to ship foreign
libraries. &lt;a href=&#34;https://github.com/Shinmera/deploy&#34;&gt;Deploy&lt;/a&gt; to the
rescue. Edit your .asd file slightly to have:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;:defsystem-depends-on (:deploy)  ;; (ql:quickload &amp;quot;deploy&amp;quot;) before
:build-operation &amp;quot;deploy-op&amp;quot;     ;; instead of &amp;quot;program-op&amp;quot; as above
:build-pathname &amp;quot;my-webapp&amp;quot;  ;; doesn&#39;t change
:entry-point &amp;quot;my-webapp:main&amp;quot;  ;; doesn&#39;t change
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Build the app again with &lt;code&gt;asdf:make&lt;/code&gt;, and see how Deploy discovers and
ships in the required foreign libraries: libssl.so, libosicat.so, libmagic.so…&lt;/p&gt;

&lt;p&gt;It puts the final binary and the .so libraries in a &lt;code&gt;bin/&lt;/code&gt;
directory. This is what you&amp;rsquo;ll have to ship.&lt;/p&gt;

&lt;p&gt;I can now build my web app, send it to my VPS and see it live \o/&lt;/p&gt;

&lt;p&gt;One more thing. We don&amp;rsquo;t want to ship &lt;code&gt;libssl&lt;/code&gt; and &lt;code&gt;libcrypto&lt;/code&gt;, so we
ask Deploy to not ship them. We prefer to rely on the target OS.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; .asd
;; Deploy may not find libcrypto on your system.
;; But anyways, we won&#39;t ship it to rely instead
;; on its presence on the target OS.
(require :cl+ssl)  ; sometimes necessary.
#+linux (deploy:define-library cl+ssl::libssl :dont-deploy T)
#+linux (deploy:define-library cl+ssl::libcrypto :dont-deploy T)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&amp;rsquo;s also a hack if you have an issue with ASDF trying to update itself… see the skeleton: &lt;a href=&#34;https://github.com/vindarel/cl-cookieweb&#34;&gt;https://github.com/vindarel/cl-cookieweb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be exhaustive, here&amp;rsquo;s how to catch a user&amp;rsquo;s &lt;code&gt;C-c&lt;/code&gt; and stop our app
correctly. By default, you would get a full backtrace. Yuk.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun main ()
  (start-app :port 9003)
  ;; with bordeaux-threads
  (handler-case (bt:join-thread (find-if (lambda (th)
                                             (search &amp;quot;hunchentoot&amp;quot; (bt:thread-name th)))
                                         (bt:all-threads)))
    (#+sbcl sb-sys:interactive-interrupt
      #+ccl  ccl:interrupt-signal-condition
      #+clisp system::simple-interrupt-condition
      #+ecl ext:interactive-interrupt
      #+allegro excl:interrupt-signal
      () (progn
           (format *error-output* &amp;quot;Aborting.~&amp;amp;&amp;quot;)
           (clack:stop *server*)
           (uiop:quit 1)) ;; portable exit, included in ASDF, already loaded.
    ;; for others, unhandled errors (we might want to do the same).
    (error (c) (format t &amp;quot;Woops, an unknown error occured:~&amp;amp;~a~&amp;amp;&amp;quot; c)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Debian package for every Quicklisp system: &lt;a href=&#34;http://margaine.com/2015/12/22/quicklisp-packagecloud-debian-packages.html&#34;&gt;http://margaine.com/2015/12/22/quicklisp-packagecloud-debian-packages.html&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;multiplatform-delivery-with-electron-ceramic&#34;&gt;Multiplatform delivery with Electron (Ceramic)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://ceramic.github.io/&#34;&gt;Ceramic&lt;/a&gt; makes all the work for us.&lt;/p&gt;

&lt;p&gt;It is as simple as this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Load Ceramic and our app
(ql:quickload &#39;(:ceramic :our-app))

;; Ensure Ceramic is set up
(ceramic:setup)
(ceramic:interactive)

;; Start our app (here based on the Lucerne framework)
(lucerne:start our-app.views:app :port 8000)

;; Open a browser window to it
(defvar window (ceramic:make-window :url &amp;quot;http://localhost:8000/&amp;quot;))

;; start Ceramic
(ceramic:show-window window)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we can ship this on Linux, Mac and Windows.&lt;/p&gt;

&lt;p&gt;More:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ceramic applications are compiled down to native code, ensuring both performance and enabling you to deliver closed-source, commercial applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(so no need to minify our JS)&lt;/p&gt;

&lt;p&gt;with one more line:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ceramic.bundler:bundle :ceramic-hello-world
                                 :bundle-pathname #p&amp;quot;/home/me/app.tar&amp;quot;)
Copying resources...
Compiling app...
Compressing...
Done!
#P&amp;quot;/home/me/app.tar&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This last line was buggy for us.&lt;/p&gt;

&lt;h1 id=&#34;deployment&#34;&gt;Deployment&lt;/h1&gt;

&lt;p&gt;When you build a self-contained binary (see above, &amp;ldquo;Shipping&amp;rdquo;), deployment gets easy.&lt;/p&gt;

&lt;h2 id=&#34;manually&#34;&gt;Manually&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;sbcl --load &amp;lt;my-app&amp;gt; --eval &#39;(start-my-app)&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For example, a &lt;code&gt;run&lt;/code&gt; Makefile target:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;run:
	sbcl --load my-app.asd \
	     --eval &#39;(ql:quickload :my-app)&#39; \
	     --eval &#39;(my-app:start-app)&#39;  ;; given this function starts clack or hunchentoot.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this keeps sbcl in the foreground. We can use &lt;code&gt;tmux&lt;/code&gt; to put it in background, or use Systemd.&lt;/p&gt;

&lt;p&gt;Then, we need of a task supervisor, that will restart our app on failures, start it after a reboot, handle logging. See the section below and example projects.&lt;/p&gt;

&lt;h2 id=&#34;with-clack-http-quickdocs-org-clack&#34;&gt;with &lt;a href=&#34;http://quickdocs.org/clack/&#34;&gt;Clack&lt;/a&gt;&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ clackup app.lisp
Hunchentoot server is started.
Listening on localhost:5000.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;with-docker&#34;&gt;with Docker&lt;/h2&gt;

&lt;p&gt;So we have various implementations ready to use: sbcl, ecl, ccl… with Quicklisp well configured.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci&#34;&gt;https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;on-heroku&#34;&gt;On Heroku&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&#34;https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp&#34;&gt;heroku-buildpack-common-lisp&lt;/a&gt; and the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#deployment&#34;&gt;Awesome CL#deploy&lt;/a&gt; section.&lt;/p&gt;

&lt;h2 id=&#34;systemd-daemonizing-restarting-in-case-of-crashes-handling-logs&#34;&gt;Systemd: daemonizing, restarting in case of crashes, handling logs&lt;/h2&gt;

&lt;p&gt;Generally, this depends on your system. But most GNU/Linux distros now come with Systemd. Write a service file like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ /etc/systemd/system/my-app.service
[Unit]
Description=stupid simple example

[Service]
WorkingDirectory=/path/to/your/app
ExecStart=/usr/bin/sbcl --load run.lisp  # your command, full path
Type=simple
Restart=always
RestartSec=10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One gotcha is that your app must be run on the foreground. See the
threads snippet above in Shipping, and add it when running the app
from sources too. Otherwise, you&amp;rsquo;ll see a &amp;ldquo;compilation unit aborted,
caught 1 fatal error condition&amp;rdquo; error. That&amp;rsquo;s simply your Lisp
quitting too early.&lt;/p&gt;

&lt;p&gt;Run this command to start the service:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo systemctl start my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to check its status:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;systemctl status my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Systemd &lt;strong&gt;handles logging for you&lt;/strong&gt;. We write to stdout or stderr, it writes logs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;journalctl -u my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;use &lt;code&gt;-f -n 30&lt;/code&gt; to see live updates of logs.&lt;/p&gt;

&lt;p&gt;This tells Systemd to handle crashes and to &lt;strong&gt;restart the app&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Restart=always
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it can &lt;strong&gt;start the app after a reboot&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Install]
WantedBy=basic.target
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to enable it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo systemctl enable my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;debugging-sbcl-error-ensure-space-failed-to-allocate-n-bytes&#34;&gt;Debugging SBCL error: ensure_space: failed to allocate n bytes&lt;/h2&gt;

&lt;p&gt;If you get this error with SBCL on your server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mmap: wanted 1040384 bytes at 0x20000000, actually mapped at 0x715fa2145000
ensure_space: failed to allocate 1040384 bytes at 0x20000000
(hint: Try &amp;quot;ulimit -a&amp;quot;; maybe you should increase memory limits.)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then disable &lt;a href=&#34;https://en.wikipedia.org/wiki/Address_space_layout_randomization&#34;&gt;ASLR&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo bash -c &amp;quot;echo 0 &amp;gt; /proc/sys/kernel/randomize_va_space&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;connecting-to-a-remote-swank-server&#34;&gt;Connecting to a remote Swank server&lt;/h2&gt;

&lt;p&gt;Little example here: &lt;a href=&#34;http://cvberry.com/tech_writings/howtos/remotely_modifying_a_running_program_using_swank.html&#34;&gt;http://cvberry.com/tech_writings/howtos/remotely_modifying_a_running_program_using_swank.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It defines a simple function that prints forever:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; a little common lisp swank demo
;; while this program is running, you can connect to it from another terminal or machine
;; and change the definition of doprint to print something else out!
;; (ql:quickload &#39;(:swank :bordeaux-threads))

(require :swank)
(require :bordeaux-threads)

(defparameter *counter* 0)

(defun dostuff ()
  (format t &amp;quot;hello world ~a!~%&amp;quot; *counter*))

(defun runner ()
  (bt:make-thread (lambda ()
                    (swank:create-server :port 4006)))
  (format t &amp;quot;we are past go!~%&amp;quot;)
  (loop while t do
       (sleep 5)
       (dostuff)
       (incf *counter*)))

(runner)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On our server, we run it with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sbcl --load demo.lisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we do port forwarding on our development machine:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh -L4006:127.0.0.1:4006 username@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will securely forward port 4006 on the server at example.com to
our local computer&amp;rsquo;s port 4006 (swanks accepts connections from
localhost).&lt;/p&gt;

&lt;p&gt;We connect to the running swank with &lt;code&gt;M-x slime-connect&lt;/code&gt;, typing in
port 4006.&lt;/p&gt;

&lt;p&gt;We can write new code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun dostuff ()
  (format t &amp;quot;goodbye world ~a!~%&amp;quot; *counter*))
(setf *counter* 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and eval it as usual with &lt;code&gt;M-x slime-eval-region&lt;/code&gt; for instance. The output should change.&lt;/p&gt;

&lt;p&gt;There are more pointers on CV Berry&amp;rsquo;s page.&lt;/p&gt;

&lt;h2 id=&#34;hot-reload&#34;&gt;Hot reload&lt;/h2&gt;

&lt;p&gt;When we run the app as a script we get a Lisp REPL, so we can
hot-reload the running web app. Here we demonstrate a recipe to update
it remotely.&lt;/p&gt;

&lt;p&gt;Example taken from &lt;a href=&#34;https://github.com/tarballs-are-good/quickutil/blob/master/quickutil-server/&#34;&gt;Quickutil&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It has a Makefile target:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;hot_deploy:
	$(call $(LISP), \
		(ql:quickload :quickutil-server) (ql:quickload :swank-client), \
		(swank-client:with-slime-connection (conn &amp;quot;localhost&amp;quot; $(SWANK_PORT)) \
			(swank-client:slime-eval (quote (handler-bind ((error (function continue))) \
				(ql:quickload :quickutil-utilities) (ql:quickload :quickutil-server) \
				(funcall (symbol-function (intern &amp;quot;STOP&amp;quot; :quickutil-server))) \
				(funcall (symbol-function (intern &amp;quot;START&amp;quot; :quickutil-server)) $(start_args)))) conn)) \
		$($(LISP)-quit))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It has to be run on the server (a simple fabfile command can call this
through ssh). Beforehand, a &lt;code&gt;fab update&lt;/code&gt; has run &lt;code&gt;git pull&lt;/code&gt; on the
server, so new code is present but not running. It connects to the
local swank server, loads the new code, stops and starts the app in a
row.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;demo-fetching-the-github-rest-api-with-common-lisp&#34;&gt;Demo: fetching the GitHub REST API with Common Lisp&lt;/h2&gt;

&lt;p&gt;In &lt;a href=&#34;https://www.youtube.com/watch?v=TAtwcBh1QLg&#34;&gt;this video&lt;/a&gt; I show you how to create a new project and we explore
the Lisp ecosystem to make API calls, notably how to fire HTTP
requests and parse JSON. We develop in Emacs and SLIME and in the end
we get a Lisp library AND an application for the command line. Hope
you enjoy the ride.&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/TAtwcBh1QLg&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>New video: how to request a REST API in Common Lisp: fetching the GitHub API 🎥</title>
      <link>/blog/new-video-how-to-request-a-web-api-with-common-lisp/</link>
      <pubDate>Sat, 11 Jun 2022 11:43:31 +0200</pubDate>
      
      <guid>/blog/new-video-how-to-request-a-web-api-with-common-lisp/</guid>
      <description>&lt;p&gt;A few weeks ago, I put together a new Lisp video. It&amp;rsquo;s cool, sound on, &amp;lsquo;til the end ;)&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/TAtwcBh1QLg&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;I want to show how to (quickly) do practical, real-world stuff in
Lisp. Here, how to request a web API. We create a new full-featured
project with my project skeleton, we study the GitHub API, and we go
ahead.&lt;/p&gt;

&lt;p&gt;I develop in Emacs with Slime, but in the end we also build a
binary, so we have a little application that works on the command line
(note that I didn&amp;rsquo;t use SBCL&amp;rsquo;s core compression, we could have a
lighter binary of around 30MB).&lt;/p&gt;

&lt;p&gt;I use the libraries: Dexador for HTTP requests, the Jonathan and then
the Shasht JSON libraries, as well as Access and Serapeum to help with
accessing, creating and viewing hash-tables.&lt;/p&gt;

&lt;p&gt;Thanks for the comments already :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tks for that&amp;hellip; it&amp;rsquo;s amazing.&lt;/p&gt;

&lt;p&gt;excellent&lt;/p&gt;

&lt;p&gt;Thank you, that was a great video! I plan to get the udemy course now based on this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are my previous ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=XFc513MJjos&#34;&gt;How to create a new full-featured Common Lisp project (with my project generator)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=KsHxgP3SRTs&#34;&gt;Interactively fixing failing tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to do more but damn, it takes time. You can push me for more :)&lt;/p&gt;

&lt;p&gt;Last notes:&lt;/p&gt;

&lt;p&gt;I had fun with the soundtrack :)&lt;/p&gt;

&lt;p&gt;I edit the video with the latest &lt;a href=&#34;https://kdenlive.org/&#34;&gt;Kdenlive&lt;/a&gt; with the snap package and it&amp;rsquo;s great for me.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Video: Create a Common Lisp project from scratch with our project generator 🎥</title>
      <link>/blog/video-create-a-lisp-project-with-our-project-generator/</link>
      <pubDate>Wed, 11 May 2022 11:43:31 +0200</pubDate>
      
      <guid>/blog/video-create-a-lisp-project-with-our-project-generator/</guid>
      <description>&lt;p&gt;In this video I want to demo real-world Lisp stuff I had trouble finding tutorials for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to create a CL project:

&lt;ul&gt;
&lt;li&gt;what&amp;rsquo;s in the .asd file?&lt;/li&gt;
&lt;li&gt;what&amp;rsquo;s a simple package definition?&lt;/li&gt;
&lt;li&gt;how do we load everything in our editor (Emacs and SLIME here)?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;how to set up tests?

&lt;ul&gt;
&lt;li&gt;and how to run them from the terminal?&lt;/li&gt;
&lt;li&gt;and (WTF) how to get the correct exit code????&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;how to build a binary in order to run our app from the terminal?

&lt;ul&gt;
&lt;li&gt;and so, how to get command-line arguments?&lt;/li&gt;
&lt;li&gt;but also, can I run my app from sources, without building a binary?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;what&amp;rsquo;s Roswell and how do I share my app with it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&amp;rsquo;s find out (it&amp;rsquo;s 5 minutes long):&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/XFc513MJjos&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;I use my project generator:
&lt;a href=&#34;https://github.com/vindarel/cl-cookieproject&#34;&gt;cl-cookieproject&lt;/a&gt;. See
setup, alternatives, limitations and TODOs there. You will also find a
similar generator for web projects.&lt;/p&gt;

&lt;p&gt;If you find it useful, share the video!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Writing an interactive web app in Common Lisp: Hunchentoot then CLOG</title>
      <link>/blog/clog-contest/</link>
      <pubDate>Thu, 28 Apr 2022 15:23:14 +0200</pubDate>
      
      <guid>/blog/clog-contest/</guid>
      <description>

&lt;p&gt;We want a web app to display a list of data and have an input field to interactively filter it.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll start with a simple, regular web app built with
Hunchentoot. We&amp;rsquo;ll have a search input to filter our data, and we&amp;rsquo;ll see that to be more interactive, typically to filter out the results as the user types, we&amp;rsquo;ll need more than basic HTTP requests. We&amp;rsquo;ll need some JavaScript. But we&amp;rsquo;ll reach this level of interactivity with CLOG (and no JavaScript).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DISCLAIMER: this post is my entry for the &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/tpr0bu/common_lisp_50_tutorial_contest_3_winners/&#34;&gt;CLOG contest&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let&amp;rsquo;s install our first libraries: Hunchentoot for the web server, Djula for the HTML templates, str for a string utility.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+(or)
(ql:quickload &#39;(&amp;quot;hunchentoot&amp;quot; &amp;quot;djula&amp;quot; &amp;quot;str&amp;quot;))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create a package for our experiments, and we &amp;ldquo;enter&amp;rdquo; it. I use UIOP&amp;rsquo;s &lt;code&gt;define-package&lt;/code&gt; because it throws less warnings than &lt;code&gt;defpackage&lt;/code&gt; when we add and remove symbols. It also has more features (&lt;code&gt;:reexport&lt;/code&gt;) that I don&amp;rsquo;t use here.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(uiop:define-package :clog-contest
    (:use :cl))

(in-package :clog-contest)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK. We define a route. It takes one GET parameter, for demo purposes.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hunchentoot:define-easy-handler (root-route :uri &amp;quot;/&amp;quot;) (name)
  (format nil &amp;quot;Hey~@[ ~A~]!&amp;quot; name))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start the server:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *server* (make-instance &#39;hunchentoot:easy-acceptor :port 6789))
(hunchentoot:start *server*)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and access &lt;a href=&#34;http://localhost:6789/&#34;&gt;http://localhost:6789/&lt;/a&gt;
Now let&amp;rsquo;s create our products. We quickly define a class containing an ID, a title and a price.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass product ()
  ((id :initarg :id :accessor product-id :type integer
       :documentation &amp;quot;Unique ID&amp;quot;)
   (title :initarg :title :accessor product-title :type string)
   (price :initarg :price :accessor product-price :type integer)))

(defvar *product-id* 1
  &amp;quot;Stupid counter to increment our unique product ID.
  Normally this is given by a DB.&amp;quot;)

(defparameter *products* &#39;() &amp;quot;A list of products.&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We are going to create random testing products, so let&amp;rsquo;s have a couple helpers to create random titles and prices.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun random-price ()
  &amp;quot;Return an integer between 1 and 10.000 (price is expressed in cents).&amp;quot;
  (1+ (random 9999)))

(defparameter *title-part-1* (list &amp;quot;pretty&amp;quot; &amp;quot;little&amp;quot; &amp;quot;awesome&amp;quot; &amp;quot;white&amp;quot; &amp;quot;blue&amp;quot;))
(defparameter *title-part-2* (list &amp;quot;book&amp;quot; &amp;quot;car&amp;quot; &amp;quot;laptop&amp;quot; &amp;quot;travel&amp;quot; &amp;quot;screwdiver&amp;quot;))
(defun random-title ()
  (let ((index (random (length *title-part-1*)))
        (index-2 (random (length *title-part-2*))))
    (format nil &amp;quot;~a ~a&amp;quot; (elt *title-part-1* index) (elt *title-part-2* index-2))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;try it out:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+(or)
(random-title)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We get titles like &amp;ldquo;white book&amp;rdquo;, &amp;ldquo;little car&amp;rdquo;, etc.
Now, for testing purposes, we create a 100 dummy product instances:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun gen-test-products (&amp;amp;optional (nb 100))
  (dotimes (i nb)
    (push (make-instance &#39;product
                         :id (incf *product-id*)
                         :title (random-title)
                         :price (random-price))
          *products*)))

(defun reset-test-products ()
  (setf *products* nil))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Try it and we get:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
*products*
(#&amp;lt;PRODUCT {1005B29363}&amp;gt; #&amp;lt;PRODUCT {1005B29113}&amp;gt; #&amp;lt;PRODUCT {1005B28EC3}&amp;gt;
 #&amp;lt;PRODUCT {1005B28C73}&amp;gt; #&amp;lt;PRODUCT {1005B28A23}&amp;gt; #&amp;lt;PRODUCT {1005B287D3}&amp;gt;
 …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Implement the &lt;code&gt;print-object&lt;/code&gt; method if you want nice-looking product literals. See the Cookbook.
&lt;br&gt;
Now let&amp;rsquo;s display the products in the browser. We will redefine our route.
We make sure to extract the view logic in functions.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(defun print-product (it &amp;amp;optional (stream nil))
  &amp;quot;Print a product title and price on STREAM (return a new string by default).&amp;quot;
  (format stream &amp;quot;~a - ~f~&amp;amp;&amp;quot;
          (str:fit 20 (product-title it))  ;; the fit function was merged recently.
          (/ (product-price it) 100)))

(defun print-products (products)
  &amp;quot;Return a list of products as a string (dummy, for tests purposes).&amp;quot;
  (with-output-to-string (s)
    (format s &amp;quot;Products:~&amp;amp;&amp;quot;)
    (dolist (it products)
      (print-product it s))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
CL-USER&amp;gt; (print-products (subseq *products* 0 10))

&amp;quot;Products:
pretty car           -   22.26
awesome travel       -   13.87
little screwdiver    -   35.6
white laptop         -   6.08
little book          -   27.57
white laptop         -   42.63
blue travel          -   93.8
blue car             -   29.99
pretty car           -   38.95
little screwdiver    -   46.99
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We tell our route to display the list of products like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(hunchentoot:define-easy-handler (root-route :uri &amp;quot;/&amp;quot;) ()
  (print-products *products*))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We see something, but it&amp;rsquo;s stupid to return text to the browser. We need templates.
We&amp;rsquo;ll use Djula templates. And we&amp;rsquo;ll steal some ready-to-use pretty HTML :)&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll use &lt;a href=&#34;https://bulma.io/&#34;&gt;Bulma&lt;/a&gt; CSS because it&amp;rsquo;s simple, modern (flexbox) and just because. I don&amp;rsquo;t know all CSS frameworks out there.
I&amp;rsquo;ll do my shopping in this showcase of Bulma templates: &lt;a href=&#34;https://bulmatemplates.github.io/bulma-templates/&#34;&gt;https://bulmatemplates.github.io/bulma-templates/&lt;/a&gt; IIRC I took the &amp;ldquo;Modal Cards&amp;rdquo; one and simplified it a bit.
Our final result is:
&lt;img src=&#34;/blog/products.png&#34; alt=&#34;&#34; /&gt;
Let&amp;rsquo;s create a &lt;code&gt;templates/&lt;/code&gt; directory and create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/vindarel/bacalisp/blob/master/lisp-tutorial-clog-contest/templates/base.html&#34;&gt;base.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/vindarel/bacalisp/blob/master/lisp-tutorial-clog-contest/templates/products.html&#34;&gt;products.html&lt;/a&gt;, that inherits the base.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inside this template, we &amp;ldquo;include&amp;rdquo; the search form that we wrote in another template: &lt;a href=&#34;https://github.com/vindarel/bacalisp/blob/master/lisp-tutorial-clog-contest/templates/search-form.html&#34;&gt;search-form.html&lt;/a&gt;. It&amp;rsquo;s a way to factorize HTML code that we can re-use here and there.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The base template loads Bulma from a CDN, creates a navbar, defines a &amp;ldquo;content&amp;rdquo; block that our other templates will override, and a footer.&lt;/p&gt;

&lt;p&gt;Our products template &amp;ldquo;extends&amp;rdquo; base.html and creates the &amp;ldquo;content&amp;rdquo; block.
There we loop over a list of products given by our Hunchentoot root and display them.
But before that happens, we need to install and configure Djula to find and compile our templates.
We tell Djula to look for templates in the templates/ directory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(djula:add-template-directory &amp;quot;templates/&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that normally, I do that relatively to an .asd file, that we didn&amp;rsquo;t create yet:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(djula:add-template-directory
 (asdf:system-relative-pathname &amp;quot;myproject&amp;quot; &amp;quot;src/templates/&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you have an issue with the path on the Lisp REPL, on SLIME you can do ,cd (a comma command) to change the current working directory.
Now we define our templates:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter +base.html+ (djula:compile-template* &amp;quot;base.html&amp;quot;))
(defparameter +products.html+ (djula:compile-template* &amp;quot;products.html&amp;quot;))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As a result, you can see they are compiled templates:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
CLOG-CONTEST&amp;gt; +products.html+
#&amp;lt;DJULA::COMPILED-TEMPLATE /home/vince/bacasable/bacalisp/lisp-tutorial-clog-contest/templates/products.html {2073D30B}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, our route needs to return a template and give data to it.
Our route returns &lt;code&gt;djula:render-template*&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hunchentoot:define-easy-handler (root-route :uri &amp;quot;/&amp;quot;) ()
  (djula:render-template* +products.html+ nil
                          :products *products*))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice!
We display all products. We will accept a search query to filter them. Pagination is for later.&lt;/p&gt;

&lt;p&gt;We have an input field that defines an HTML form,
that calls the search endpoint.
We need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;to define the /search route&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;to write a dummy function to search in our products list.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(defun search-products (query &amp;amp;optional (products *products*))
  &amp;quot;Search for QUERY in the products&#39; title.
  This would be a DB call.&amp;quot;
  (loop for product in products
     when (str:containsp (str:downcase query) (str:downcase (product-title product)))
     collect product))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Try it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+(or)
(search-products &amp;quot;awesome&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the search route. It accepts one GET parameter, &lt;code&gt;q&lt;/code&gt; for &amp;ldquo;query&amp;rdquo;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(hunchentoot:define-easy-handler (search-route :uri &amp;quot;/search&amp;quot;) (q)
  (let* ((products (search-products *products* q)))
    (djula:render-template* +products.html+ nil
                            :title (format nil &amp;quot;My products - ~a&amp;quot; q)
                            :query q
                            :products products
                            :no-results-p (zerop (length products)))))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Try it, it works :)
I agree, the search algorithm is simplistic. What about multiple words, accents, typos, non-exact searches (stemming)…?&lt;/p&gt;

&lt;p&gt;Your search query is seen in the URL parameters:
&lt;a href=&#34;http://localhost:6789/search?q=travel&#34;&gt;http://localhost:6789/search?q=travel&lt;/a&gt;
That is usually a good thing. In modern single-page applications, you loose this, or you have to handle the URL construction yourself.&lt;/p&gt;

&lt;p&gt;The search required a page reload. If your app is fast, it might not be an issue.
However, if we wanted the search to be more interactive, for example showing results as we type, we would need to use JavaScript. Enters CLOG.&lt;/p&gt;

&lt;h2 id=&#34;clog&#34;&gt;CLOG&lt;/h2&gt;

&lt;p&gt;Can we make our app interactive with &lt;a href=&#34;https://github.com/rabbibotton/clog/&#34;&gt;CLOG&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Well, we can, and what&amp;rsquo;s even cooler is that the development
process is itself very interactive.  CLOG sends changes to the page
through websockets as you add or edit functionalities. As such we
can see changes in real time. For example, change a colour:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(setf (background-color *body*) :red)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and BAM, it&amp;rsquo;s red.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create another package for this new app. I&amp;rsquo;ll &amp;ldquo;use&amp;rdquo; functions and macros provided by the :clog package, as well as our previously defined :clog-contest ones (duh… we didn&amp;rsquo;t :export any yet).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(uiop:define-package :clog-contest-with-clog
    (:use :cl :clog
          :clog-contest))

(in-package :clog-contest-with-clog)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The very first steps you can do to grasp CLOG&amp;rsquo;s interactive fun is to make changes to a browser window while on the CLOG REPL.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(ql:quickload &amp;quot;clog&amp;quot;)
CL-USER&amp;gt; (in-package clog-user)
CLOG-USER&amp;gt; (clog-repl)
CLOG-USER&amp;gt; (setf (background-color *body*) &amp;quot;red&amp;quot;)
CLOG-USER&amp;gt; (create-div *body* :content &amp;quot;Hello World!&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And voilà. A browser window was opened for you.&lt;/p&gt;

&lt;p&gt;You will also find many demos here: &lt;a href=&#34;https://github.com/rabbibotton/clog/tree/main/tutorial&#34;&gt;https://github.com/rabbibotton/clog/tree/main/tutorial&lt;/a&gt;
You can run them with &lt;code&gt;(clog:run-tutorial 1)&lt;/code&gt; (by their number id).&lt;/p&gt;

&lt;p&gt;For the following, I invite you to have a look at CLOG&amp;rsquo;s common elements: &lt;a href=&#34;https://rabbibotton.github.io/clog/clog-manual.html#toc-8-common-clog-elements&#34;&gt;https://rabbibotton.github.io/clog/clog-manual.html#toc-8-common-clog-elements&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typically, to create a &lt;code&gt;div&lt;/code&gt; on a DOM element, we use &lt;code&gt;create-div&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first thing we want to start our CLOG app is the &lt;code&gt;initialize&lt;/code&gt; function. Its signature:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
initialize (on-new-window-handler &amp;amp;key (host 0.0.0.0) (port 8080) (server hunchentoot)
 (extended-routing nil) (long-poll-first nil) (boot-file /boot.html)
 (boot-function nil) (static-boot-html nil) (static-boot-js nil)
 (static-root (merge-pathnames ./static-files/ (system-source-directory clog))))

Inititalize CLOG on a socket using HOST and PORT to serve BOOT-FILE
as the default route to establish web-socket connections and static
files located at STATIC-ROOT. […]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following calls our &lt;code&gt;add-products&lt;/code&gt; function with a &lt;code&gt;body&lt;/code&gt; (CLOG object) as argument.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun start-tutorial ()
  &amp;quot;Start tutorial.&amp;quot;
  (initialize &#39;add-products)
  (open-browser))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK so what do we want to do? We want to create a search input field, and to display our products below. When the user types something, we want to &lt;em&gt;immediately&lt;/em&gt; filter the products, and re-display them.&lt;/p&gt;

&lt;p&gt;A first version where we only display products would be this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(defun add-products (body)
  (let* ((result-div (create-div body :content &amp;quot;&amp;quot;)))
    (display-products result-div (subseq clog-contest::*products* 0 10))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the &lt;code&gt;display-products&lt;/code&gt; function is below:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(defun display-products (body products)
  &amp;quot;Display these products in the page.
  Create a div per product, with a string to present the product.
  We don&#39;t create nice-looking Bulma product cards here.&amp;quot;
  (dolist (it products)
      (create-div body :content
                  (format nil &amp;quot;~a - ~a&amp;quot;
                          (clog-contest::product-id it)
                          (clog-contest::print-product it)))))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we want to handle the interactivity. The event to watch is the key up event. In CLOG, we have the &lt;code&gt;set-on-key-up&lt;/code&gt; method. It takes: a CLOG object (the DOM object it watches for events) and a handler function. This function takes two arguments: the CLOG object and the event.&lt;/p&gt;

&lt;p&gt;In our add-products function below, we create the search input and we listen the key-up event:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(defun add-products (body)
  &amp;quot;Create the search input and a div to contain the products.
  Bind the key-up event of the input field to our filter function.&amp;quot;
  (let* ((form (create-form body))
         (input (create-form-element form :input :name &amp;quot;query&amp;quot;
                                     :label
				     (create-label form :content &amp;quot;Filter product: &amp;quot;)))
         (result-div (create-div body :content &amp;quot;&amp;quot; )))

    (set-on-key-up input
                   (lambda (obj event)
                     (format t &amp;quot;:key-up, value: ~a~&amp;amp;&amp;quot; (value obj)) ; logging
                     (setf (text result-div) &amp;quot;&amp;quot;) ; this is how we erase the current content.
                     (handle-filter-product result-div obj event)))

    (display-products result-div clog-contest::*products*)))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Below, to find out what is typed in the search input, we use &lt;code&gt;(value obj)&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(defun handle-filter-product (div obj event)
  &amp;quot;Search and redisplay products.&amp;quot;
  ;TODO: wait a little latency
  (declare (ignorable event))
  (let ((query (value obj)))
    (if (&amp;gt; (length query) 2)
        (display-products div (clog-contest::search-products query))
        (print &amp;quot;waiting for more input&amp;quot;))))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It works \o/&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/blog/clog-search.gif&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;There are some caveats that need to be worked on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if you type a search query of 4 letters quickly, our handler waits for an input of at least 2 characters, but it will be fired 2 other times. That will probably fix the blickering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, as you noticed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we didn&amp;rsquo;t copy-paste a nice looking HTML template, so we have a bit of work with that :/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLOG is not at all limited to websites like this. You can create games (there is a Snake demo), multiplayer applications (there is a chat demo)… all this by doing everything in the backend, in Common Lisp, with a lot of interactivity under the fingertips. Try it out!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;By the way, this post was written in a literate style with &lt;a href=&#34;https://github.com/mmontone/erudite/&#34;&gt;Erudite&lt;/a&gt;. Everything is written in a .lisp file, and exported to markdown. Read about it &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/literate-programming-in-lisp-with-erudite/&#34;&gt;here&lt;/a&gt; and see &lt;a href=&#34;https://github.com/vindarel/bacalisp/blob/master/lisp-tutorial-clog-contest/clog-contest-tutorial.lisp&#34;&gt;its source on GitHub&lt;/a&gt;. You can &lt;code&gt;wget&lt;/code&gt; this source, open it in your editor and compile the snippets along the way.&lt;/p&gt;

&lt;p&gt;For more web stuff, see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#web-frameworks&#34;&gt;https://github.com/CodyReichert/awesome-cl#web-frameworks&lt;/a&gt; traditional web frameworks as well as Weblocks (Reblocks), CLOG, ISSR…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/web.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/web.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a demo: &lt;a href=&#34;https://github.com/vindarel/demo-web-live-reload&#34;&gt;https://github.com/vindarel/demo-web-live-reload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a demo, very similar to our product list built with Djula and Bulma CSS, a bit more complete: &lt;a href=&#34;https://github.com/vindarel/lisp-web-template-productlist&#34;&gt;https://github.com/vindarel/lisp-web-template-productlist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ISSR todo-list demo: &lt;a href=&#34;https://github.com/vindarel/demo-ISSR-djula&#34;&gt;https://github.com/vindarel/demo-ISSR-djula&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;my web project skeleton: &lt;a href=&#34;https://github.com/vindarel/cl-cookieweb&#34;&gt;https://github.com/vindarel/cl-cookieweb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a demo of Caveman and &lt;a href=&#34;https://htmx.org/&#34;&gt;htmx&lt;/a&gt;, a neat JS library that brings easy interactivity for many use cases: &lt;a href=&#34;https://github.com/rajasegar/cl-beers&#34;&gt;cl-beers&lt;/a&gt;. &amp;ldquo;htmx gives you access to AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext&amp;rdquo;. It doesn&amp;rsquo;t always replace a JS framework, but is worth considering.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Resources</title>
      <link>/resources/</link>
      <pubDate>Thu, 21 Apr 2022 07:51:49 +0100</pubDate>
      
      <guid>/resources/</guid>
      <description>

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://lisp-lang.org/&#34;&gt;lisp-lang.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;awesome-cl&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#learning-and-tutorials&#34;&gt;learning and tutorials&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://40ants.com/lisp-project-of-the-day/&#34;&gt;Lisp project of the day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/google/lisp-koans&#34;&gt;Google&amp;rsquo;s Lisp koans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lisp-tips/lisp-tips/issues/&#34;&gt;Lisp tips&lt;/a&gt; a GitHub repository where anybody can post tips an tricks.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;search libraries on&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://quickdocs.org/&#34;&gt;http://quickdocs.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;individual-sites&#34;&gt;Individual sites:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/&#34;&gt;sjl&amp;rsquo;s road to Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@MartinCracauer/a-gentle-introduction-to-compile-time-computing-part-3-scientific-units-8e41d8a727ca&#34;&gt;Martin Cracauer&amp;rsquo;s Gentle Introduction to compile-time computing&lt;/a&gt; - excellent article series&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;screencasts&#34;&gt;Screencasts:&lt;/h2&gt;

&lt;p&gt;Of course, see &lt;strong&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;my Udemy Lisp course&lt;/a&gt;&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;I also post videos on Youtube, check this out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=XFc513MJjos&#34;&gt;How to quickly create a Common Lisp project with my project generator&lt;/a&gt;: see an ASDF system definition, how to build a binary, run the project from sources, load everything in Emacs, run the test suite…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=KsHxgP3SRTs&#34;&gt;How to interactively fix failing tests&lt;/a&gt; - very short video to showcase the interactive debugger and that we can re-compile a failing function and resume the execution from where it failed to see it finally pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/XFc513MJjos&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Those ones ar great too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/playlist?list=PL2VAYZE_4wRJi_vgpjsH75kMhN4KsuzR_&#34;&gt;Little Bits of Lisp&lt;/a&gt; -
short videos on various topics: inspecting a condition, basics of
lisp&amp;rsquo;s evaluation model,…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/playlist?list=PL2VAYZE_4wRIoHsU5cEBIxCYcbHzy4Ypj&#34;&gt;Common Lisp Tutorials&lt;/a&gt;, of which &lt;a href=&#34;https://www.youtube.com/watch?v=sBcPNr1CKKw&amp;amp;index=4&amp;amp;list=PL2VAYZE_4wRIoHsU5cEBIxCYcbHzy4Ypj&#34;&gt;Emacs and Slime - useful keyboard shortcuts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=CNFr7zIfyeM&#34;&gt;Programming a message bus in Common Lisp&lt;/a&gt; - shows the interactive nature of lisp, good use of the debugger, test-driven development to shape the api, bordeaux-threads.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=_B_4vhsmRRI&#34;&gt;Marco Baringer&amp;rsquo;s SLIME Tutorial Video&lt;/a&gt; - a video showing Marco develop a package and explaining Slime and Lisp features, with many little important explanations (1 hour). It only has some rotten bits, for example it installs packages with asdf-install and not Quicklisp.&lt;/li&gt;
&lt;li&gt;Shinmera playlists:
&lt;a href=&#34;https://www.youtube.com/playlist?list=PLkDl6Irujx9MtJPRRP5KBH40SGCenztPW&#34;&gt;Treehouse&lt;/a&gt;
(game dev),
&lt;a href=&#34;https://www.youtube.com/playlist?list=PLkDl6Irujx9Mh3BWdBmt4JtIrwYgihTWp&#34;&gt;Demos&lt;/a&gt;
(of small programs).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=82o5NeyZtvw&#34;&gt;Pushing pixels with Lisp&lt;/a&gt;, and by the same author:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=a2tTpjGOhjw&amp;amp;index=20&amp;amp;list=RDxzTH_ZqaFKI&#34;&gt;CEPL demo&lt;/a&gt; - working with OpenGL&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCMV8p6Lb-bd6UZtTc_QD4zA&#34;&gt;Baggers&amp;rsquo; channels&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/playlist?list=PLbl4KVdl9U3I3MhFWgauT0cz-x7SymZmn&amp;amp;disable_polymer=true&#34;&gt;Cando: computational chemistry with Common Lisp on LLVM with Jupyter notebooks&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=XGmo0E_S46I&#34;&gt;McClim interactive GUI demos&lt;/a&gt;. &lt;a href=&#34;https://github.com/robert-strandh/McCLIM/blob/master/Examples/demodemo.lisp&#34;&gt;Code examples&lt;/a&gt;. Presentation of &lt;a href=&#34;https://www.youtube.com/watch?v=kfBmRsPRdGg&#34;&gt;Clim listener, Clim debugger, drawing objects into the GUI repl&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/channel/UC55S8D_44ge2cV10aQmxNVQ&#34;&gt;videos of the European Lisp Symposium&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and more on &lt;a href=&#34;http://www.cliki.net/Lisp%20Videos&#34;&gt;Cliki&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;some-games&#34;&gt;Some games:&lt;/h2&gt;

&lt;p&gt;and &lt;a href=&#34;https://dev.to/vindarel/common-lisp-games-2023-4m00&#34;&gt;more games (Lisp Game Jam 2023 submissions)&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://kandria.com/&#34;&gt;Kandria&lt;/a&gt; - a nice platform game launched on Steam. Check it out!&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://bohonghuang.itch.io/nano-towers&#34;&gt;nano-towers&lt;/a&gt; -  a simple tower defense game written in Common Lisp with the EON framework based on Raylib, submitted for the Spring Lisp Game Jam 2024.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvMjcyOTE1Mi8xNjI3ODI3NC5wbmc=/347x500/I9n75v.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/artchad/dmomd&#34;&gt;dmomd&lt;/a&gt; - A rogue-like RPG with turn based movement and combat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://codeberg.org/artchad/dmomd/media/branch/master/screenshots/screen-001-480x270.jpg&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://vitovan.itch.io/maze&#34;&gt;The Maze and Lost Cat&lt;/a&gt; (in-browser)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/VitoVan/lisp-game-jam-2023/main/Spring/screenshots/spring-1.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://awkravchuk.itch.io/thoughtbound&#34;&gt;Thoughtbound&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvMjEwMjc1OC8xMjM3ODk4Mi5wbmc=/original/WziYeW.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://store.steampowered.com/app/2023440/Jettatura/&#34;&gt;Jettatura&lt;/a&gt; - a challenging first-person dungeon-crawler (DRPG) with round-based combat. On Steam and planned for 2022, Q2.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://baggers.itch.io/orb&#34;&gt;Orb&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvMjUyMTE3LzEyMDYxNDUucG5n/347x500/YEFnGW.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/borodust/notalone&#34;&gt;Notalone&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvMTg2MzQ1Lzg3MjI2NC5wbmc=/347x500/6WLhIo.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://sarge.itch.io/moppu&#34;&gt;Moppu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvNTAyMzQ2LzI2MDA1NjUucG5n/347x500/hdXQvV.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://goofist.itch.io/the-price-of-a-cup-of-coffee&#34;&gt;The price of a cup of coffee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://img.itch.zone/aW1hZ2UvNTAyNzk3LzI2MDMzNDQucG5n/347x500/0svE3f.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/lisp-mirror/fruktorama&#34;&gt;Fruktorama&lt;/a&gt;, Tetris-like with fruits.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://defungames.com/&#34;&gt;Spycursion&lt;/a&gt; - &amp;ldquo;a sandbox &amp;ldquo;edutainment&amp;rdquo; MMO centered around hacking and espionage which takes place in a near-future world&amp;rdquo;. [stalled]&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>I Am Creating a Common Lisp Video Course on Udemy (free video previews) 🎥</title>
      <link>/blog/i-am-creating-a-common-lisp-video-course-on-udemy/</link>
      <pubDate>Fri, 15 Apr 2022 15:23:14 +0200</pubDate>
      
      <guid>/blog/i-am-creating-a-common-lisp-video-course-on-udemy/</guid>
      <description>

&lt;p&gt;Everyone, let me celebrate a little bit: I am creating a &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;Common Lisp
video course on the Udemy
platform&lt;/a&gt;. I&amp;rsquo;m
several dozen hours in already and it&amp;rsquo;s taking a good shape! It is so
much more time consuming to create videos than to write a tutorial O_o
But I like what&amp;rsquo;s in there already, although there isn&amp;rsquo;t everything I
want to teach, of course. I&amp;rsquo;m working on more content. Everything will
come in time, and meanwhile you can buy the course: you&amp;rsquo;ll get future
content for &amp;ldquo;free&amp;rdquo; ;) Yes the course is to sell, hopefully it will
help me concentrate more on my CL activities (BTW, dear reader, here&amp;rsquo;s
&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=2204-LISP4ALL&#34;&gt;a 50% off
coupon&lt;/a&gt;
for April, 2022, and if you are a student drop me a line). Currently 4
videos are freely viewable, and I&amp;rsquo;m also posting new videos on
Youtube (that one is on &lt;a href=&#34;https://www.youtube.com/watch?v=XFc513MJjos&#34;&gt;how to create a new Common Lisp project&lt;/a&gt; with my project generator) but more on that
later. You currently have more than 3 hours of learning material.&lt;/p&gt;

&lt;p&gt;You probably know me from my blog and my Lisp activities. I am
&lt;a href=&#34;https://github.com/vindarel/&#34;&gt;vindarel&lt;/a&gt;, I contribute to
community-based learning resources such as the
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;Cookbook&lt;/a&gt; and I use CL
in production©. Honestly, I missed a Cookbook-like resource as a
beginner. I dumped there a lot of content and must-know tricks that I
either learned the hard way, either learned by chance. But &lt;strong&gt;I still
want Common Lisp to be easier to learn&lt;/strong&gt; and, for that, there is the
video media. Consequently, &lt;strong&gt;I truely think this course is today&amp;rsquo;s
most efficient way to learn Common Lisp&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, what can you learn already in my course?&lt;/p&gt;

&lt;p&gt;I want it to be practical: you will learn Lisp the language in order
to build real-world stuff.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-1-is-how-to-get-started&#34;&gt;Chapter 1 is how to get started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-2-is-about-lisp-basics&#34;&gt;Chapter 2 is about Lisp basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-3-is-about-iteration-it-is-made-of-shorter-videos-that-typically-sum-up-in-5-minutes&#34;&gt;Chapter 3 is about iteration. It is made of shorter videos that typically sum up in 5 minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-4-teaches-everything-you-need-to-know-about-functions&#34;&gt;Chapter 4 teaches everything you need to know about functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chapter-5-shows-how-to-work-with-projects&#34;&gt;Chapter 5 shows how to work with projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#who-is-this-course-for-by-the-way&#34;&gt;Who is this course for by the way?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closing-thoughts&#34;&gt;Closing thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#addendum-the-lisp-philosophy-revealed&#34;&gt;ADDENDUM: the Lisp philosophy revealed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;!-- ![](/images/udemy-photo-laptop--lambda.png) --&gt;

&lt;p&gt;&lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;
  &lt;img src=&#34;/images/udemy-photo-laptop--lambda.png&#34; alt=&#34;Udemy&#34; width=&#34;750&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;chapter-1-is-how-to-get-started&#34;&gt;Chapter 1 is how to get started&lt;/h2&gt;

&lt;p&gt;1.1. We start by &lt;strong&gt;installing SBCL&lt;/strong&gt; on our machine (showed for Unix,
   links for Windows). This one is 15m long and is 🆓 free to
   watch. We see how to start our Lisp, how to write &amp;ldquo;hello world&amp;rdquo;, we
   understand the output, we add readline support to the SBCL default
   REPL in the terminal, we disable the interactive debugger, and we
   have a few words on Lisp implementations and GNU CLISP in
   particular.&lt;/p&gt;

&lt;p&gt;1.2. We see &lt;strong&gt;how to run Lisp code&lt;/strong&gt;, the simplest way. We write a code snippet &lt;em&gt;with a simple
   text editor&lt;/em&gt; and we run it with sbcl&amp;rsquo;s &lt;code&gt;--script&lt;/code&gt; and &lt;code&gt;--load&lt;/code&gt; flags. We
   use the &lt;code&gt;LOAD&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;1.3. We see &lt;strong&gt;how to use Portacle&lt;/strong&gt; (the ready-to-use, multiplatform
image shipping Emacs, SBCL, Quicklisp, Git and a couple handy Emacs
packages).&lt;/p&gt;

&lt;h2 id=&#34;chapter-2-is-about-lisp-basics&#34;&gt;Chapter 2 is about Lisp basics&lt;/h2&gt;

&lt;p&gt;2.1. I heard Lisp beginners who needed &lt;strong&gt;a recap on the Lisp syntax
and the evualation model&lt;/strong&gt;. This one is also 🆓 available to everyone. We
see: the prefix notation, that everything is an expression, the
evaluation model (and the exception of macros). Code is data is code… right?&lt;/p&gt;

&lt;p&gt;2.2. How to define &lt;strong&gt;variables&lt;/strong&gt;, at the toplevel or locally. How to
lexically re-bind dynamic variables, the gotcha, the alternative.&lt;/p&gt;

&lt;p&gt;2.3. and &lt;strong&gt;conditionals&lt;/strong&gt; (if, when, #+or…)&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s it for now for this chapter (yes, we&amp;rsquo;ll see data structures, but for now I refer you to the Cookbook, on the page that I also authored. You are armed to read it.).&lt;/p&gt;

&lt;h2 id=&#34;chapter-3-is-about-iteration-it-is-made-of-shorter-videos-that-typically-sum-up-in-5-minutes&#34;&gt;Chapter 3 is about iteration. It is made of shorter videos that typically sum up in 5 minutes&lt;/h2&gt;

&lt;p&gt;…what took me a long time to learn or discover, a way longer time to admit.&lt;/p&gt;

&lt;p&gt;3.1 &lt;strong&gt;Iterating over lists and vectors&lt;/strong&gt; (with 🆓 free preview). &lt;code&gt;loop&lt;/code&gt;, &lt;code&gt;dolist&lt;/code&gt; and other libraries of the ecosystem.&lt;/p&gt;

&lt;p&gt;3.2 then: &lt;strong&gt;Iterating over a hash-table&lt;/strong&gt; keys and values. We see 5 different ways in 5 minutes.&lt;/p&gt;

&lt;p&gt;3.3 &lt;strong&gt;Iterating a fixed or infinite number of times&lt;/strong&gt;, and we take the
opportunity to build our first read-eval-print-loop.&lt;/p&gt;

&lt;p&gt;3.4. Here, we take a &lt;strong&gt;high level overview of &lt;code&gt;loop&lt;/code&gt;&lt;/strong&gt; and we study some gotchas. We see a practical example from an answer to last year&amp;rsquo;s Advent Of Code.&lt;/p&gt;

&lt;h2 id=&#34;chapter-4-teaches-everything-you-need-to-know-about-functions&#34;&gt;Chapter 4 teaches everything you need to know about functions&lt;/h2&gt;

&lt;p&gt;(with a sneak peak into CLOS):&lt;/p&gt;

&lt;p&gt;4.1. &lt;strong&gt;How to create named functions&lt;/strong&gt;, how to handle all types of arguments (🆓 free preview). We see &lt;code&gt;defun&lt;/code&gt;, returned values, required arguments, optional arguments, key arguments, how to set a default value, how to know if an argument was supplied, &lt;code&gt;&amp;amp;rest&lt;/code&gt;, example of &lt;code&gt;apply&lt;/code&gt;, feature flags…&lt;/p&gt;

&lt;p&gt;4.2. Referencing functions, redefining functions locally, accessing documentation&lt;/p&gt;

&lt;p&gt;4.3. &lt;strong&gt;Multiple Return Values&lt;/strong&gt; (they are NOT like returning a list or a tuple!!!)&lt;/p&gt;

&lt;p&gt;4.4. &lt;strong&gt;Higher Order Functions&lt;/strong&gt;: how to give functions as arguments, &lt;code&gt;member&lt;/code&gt;, the &lt;code&gt;:test&lt;/code&gt; keyword, &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;mapcar&lt;/code&gt;, &lt;code&gt;lambda&lt;/code&gt;, how to generate functions, what are symbols, setf symbol-function. A word on currying and being a Lisp-2.&lt;/p&gt;

&lt;p&gt;4.5. &lt;strong&gt;Closures&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4.6. setf functions&lt;/p&gt;

&lt;p&gt;4.7. &lt;strong&gt;Generic Functions&lt;/strong&gt; (quick intro to CLOS): they allow to write functions that dynamically dispatch on the type of their arguments. What we see (quickly): &lt;code&gt;defmethod&lt;/code&gt;, &lt;code&gt;defgeneric&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;and, lastly (for now):&lt;/p&gt;

&lt;h2 id=&#34;chapter-5-shows-how-to-work-with-projects&#34;&gt;Chapter 5 shows how to work with projects&lt;/h2&gt;

&lt;!-- How to create a project from scratch or how to work with an existing project. --&gt;

&lt;p&gt;5.1 &lt;strong&gt;How to work with an existing project&lt;/strong&gt;. ASDF, Quicklisp, SLIME shortcuts, some useful &lt;code&gt;asdf&lt;/code&gt; functions…&lt;/p&gt;

&lt;p&gt;5.2. &lt;strong&gt;How to create a new project&lt;/strong&gt;. As a bonus, see again my new
video on Youtube: &lt;a href=&#34;https://www.youtube.com/watch?v=XFc513MJjos&#34;&gt;Common Lisp: how to create a new
project&lt;/a&gt; (demo of my
project generator).&lt;/p&gt;

&lt;p&gt;5.3. What are &lt;strong&gt;systems and packages&lt;/strong&gt; anyways? Demo. Gotcha when creating a package. Finding all external symbols of a package.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Soooo&lt;/p&gt;

&lt;h2 id=&#34;who-is-this-course-for-by-the-way&#34;&gt;Who is this course for by the way?&lt;/h2&gt;

&lt;p&gt;I must warn that this course is &lt;em&gt;not&lt;/em&gt; for total newcomers in programming. You should know what variables and functions are. You should knew that Common Lisp is a language of the Lisp family! (I tell more in the presentation video, but still).&lt;/p&gt;

&lt;p&gt;Lisp newbies are welcome because I introduce Lisp basics (syntax,
evaluation model) and I show how to install everything. It would
help if you know what is a language of the Lisp family.&lt;/p&gt;

&lt;p&gt;This course is mainly targetting young(ish) profesional developers
like me, who feel they deserve a more fun, comfy, compiled and fast
programming language.&lt;/p&gt;

&lt;p&gt;It is for Python or JavaScript programmers frustrated by the unstability of their ecosystem,&lt;/p&gt;

&lt;p&gt;for students of computer science who want to discover why Lisp still has un-matched alien technology inside (and maybe for *your* students?),&lt;/p&gt;

&lt;p&gt;for Clojurists who want to transition quickly to a bare-metal Lisp,&lt;/p&gt;

&lt;p&gt;or simply for your friend or colleague to whom you are trying to sell the power of Lisp ;)&lt;/p&gt;

&lt;!-- If you want Common Lisp to continue to strive, help the guys who help doing it :D --&gt;

&lt;h2 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h2&gt;

&lt;p&gt;If you are already a programmer: you can watch the videos at speed 1.25 or higher, but try to not skip content. You can start by the chapter of your choice. Use the captions, they are manually edited.&lt;/p&gt;

&lt;p&gt;Thanks kindly for your support in that new journey of mine! Hope you&amp;rsquo;ll enjoy the content (I know you&amp;rsquo;ll learn a few tricks).&lt;/p&gt;

&lt;p &gt;
 &lt;strong style=&#34;box-shadow: none&#34;&gt; Learn Common Lisp now! It&#39;s a tool for a lifetime.
 &lt;/strong&gt;
 &lt;/p&gt;

&lt;p &gt;
 &lt;strong style=&#34;box-shadow: none&#34;&gt; And have fun!
 &lt;/strong&gt;
 &lt;/p&gt;

&lt;!-- =&gt; [https://www.udemy.com/course/common-lisp-programming/](https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358) --&gt;

&lt;p class=&#34;announce&#34;
         style=&#34;background-color: #f48224;
    color: white;
    padding: 1em;
    margin: 1em 0 1em 0;
    text-align: center;
    opacity: 0.9;
&#34;&gt;
           🎥  

  &lt;strong style=&#34;box-shadow: none&#34;&gt;
        &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34; style=&#34;color: white&#34;&gt;
        Common Lisp: from novice to effective developer
        &lt;/a&gt;
  &lt;/strong&gt;
           🎥
&lt;/p&gt;

&lt;hr /&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/&#34;&gt;project&amp;rsquo;s GitHub&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;request: &lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos/issues/3&#34;&gt;debugging chapter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;a known issue: I started with a meh microphone. I bought a new one, sound is now good, but older videos were not re-captured yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;addendum-the-lisp-philosophy-revealed&#34;&gt;ADDENDUM: the Lisp philosophy revealed&lt;/h2&gt;

&lt;p&gt;Udemy auto-generates captions for your videos. You can manually edit
them… but sometimes I was tempted not to, as they can reveal some hidden
truth^^&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I can see my new prince here&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;reveals my respect for &amp;ldquo;print&amp;rdquo;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Survivor needs votes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I never thought about that O_o (that&amp;rsquo;s for &amp;ldquo;the variable name is unbound&amp;rdquo;)&lt;/p&gt;

&lt;p&gt;CL might be more active than you think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Google and China&amp;rsquo;s also actively contributes, as we said.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;for &amp;ldquo;Google engineers also actively contribute to the SBCL implementation&amp;rdquo;. My cute accent is well interpreted beyond hopes (and it is not wrong, hello fellow chinese lispers o/ ).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;and yes, I use communism prediction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;ldquo;I use CL in production&amp;rdquo;…&lt;/p&gt;

&lt;p&gt;Lisp is used in more places than you think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to give you a few tips for when you are dealing with cruise people&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;aka &amp;ldquo;for when you are dealing with macros&amp;rdquo;. And yes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;my crew is special&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;indeed :p &amp;ldquo;the loop macro is special&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;We knew a so called Lisp curse… there&amp;rsquo;s a conspiracy too!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the conspiracy control key&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;is &amp;ldquo;C-c C-k&amp;rdquo;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;and we can create with controversy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;instead of &amp;ldquo;and we can quit with C-c C-c&amp;rdquo;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;you have to respect the water&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you have to respect the order.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;discipline is nested in your code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;for &amp;ldquo;deeply nested in your code&amp;rdquo;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;ll show you from Oslo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;= &amp;ldquo;I&amp;rsquo;ll show you from Emacs and Slime&amp;rdquo;, that&amp;rsquo;s quite an interpretation but Emacs is a great place to live in too.&lt;/p&gt;

&lt;p&gt;And I also like that one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m actually a terrific&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;that is the translation of the name &amp;ldquo;Eitaro Fukamachi&amp;rdquo;. Add &amp;ldquo;coder&amp;rdquo; and that matches :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Who&#39;s using Common Lisp ?</title>
      <link>/who/</link>
      <pubDate>Tue, 05 Apr 2022 07:51:49 +0100</pubDate>
      
      <guid>/who/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Everyone says “Nobody uses Lisp” and Lispers say “Yes they do, there’s ITA, and, um, Autocad, and, uh, oh yeah, Paul Graham wrote Viaweb in Lisp!” Not very helpful for either side.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We now have a list: &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;&lt;strong&gt;awesome-lisp-companies&lt;/strong&gt;&lt;/a&gt;. It isn&amp;rsquo;t official nor exhaustive, but it&amp;rsquo;s way better than the past situaton.&lt;/p&gt;

&lt;p&gt;Of course, see also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://lisp-lang.org/success/&#34;&gt;lisp-lang.org&amp;rsquo;s success stories&lt;/a&gt; for
a showcase of projects and companies in aerospace, AI &amp;amp; Machine
Learning, Science, Graphics etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://franz.com/success/&#34;&gt;Franz.com success stories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/success-stories/index.html&#34;&gt;LispWorks&amp;rsquo; success stories&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a nutshell, what&amp;rsquo;s Common Lisp good for? Let&amp;rsquo;s quote Kent Pitman&amp;rsquo;s famous answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But please don&amp;rsquo;t assume this is an exhaustive list, and please don&amp;rsquo;t assume Lisp is only useful for Animation and Graphics, AI, Bioinformatics, B2B and Ecommerce, Data Mining, EDA/Semiconductor applications, Expert Systems, Finance, Intelligent Agents, Knowledge Management, Mechanical CAD, Modeling and Simulation, Natural Language, Optimization, Research, Risk Analysis, Scheduling, Telecom, and Web Authoring just because these are the only things they happened to list. Common Lisp really is a general language capable of a lot more than these few incidental application areas, even if this web page doesn&amp;rsquo;t totally bring that out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(and this list doesn&amp;rsquo;t mention that it was used for auto-piloting the
Deep Space 1 spaceship by the NASA for several days).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Here&amp;rsquo;s a shorter list of companies using CL in production©.&lt;/p&gt;

&lt;p&gt;Quantum computing companies use CL, especially SBCL:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://rigetti.com/about&#34;&gt;&lt;strong&gt;Rigetti&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They already sponsored a Quicklisp development. They chose Common Lisp (SBCL). &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7ifq92/lisp_at_the_frontier_of_computation_by_robert/&#34;&gt;Video&lt;/a&gt;. &lt;em&gt;Their&lt;/em&gt; Lisp even runs 40% faster than &lt;em&gt;their&lt;/em&gt; C code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/rigetti.png&#34; alt=&#34;rigetti&#34; width=&#34;750&#34; style=&#34;z-index: 100&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://www.dwavesys.com&#34;&gt;&lt;strong&gt;D-wave systems&lt;/strong&gt;&lt;/a&gt;, &amp;ldquo;quantum processor development&amp;rdquo;. &amp;ldquo;The software is implemented in Common Lisp (SBCL) and is an integral part of the quantum computing system.&amp;rdquo; &lt;a href=&#34;https://lispjobs.wordpress.com/2015/03/16/software-developer-for-quantum-processor-development-group-d-wave-systems-vancouver-british-columbia/&#34;&gt;lispjobs announce&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/dwave.png&#34; alt=&#34;dwave&#34; width=&#34;750&#34; style=&#34;z-index: 100&#34;/&gt;&lt;/p&gt;

&lt;p&gt;And there&amp;rsquo;s at least also &lt;a href=&#34;https://www.hrl.com/&#34;&gt;HRL Laboratories&lt;/a&gt; in the Quantum space (I am not counting defunkt Quantum companies). They are &amp;ldquo;one of the world&amp;rsquo;s premier physical science and engineering research laboratories. [They] engage in the development of a full quantum device and computation stack, including an optimizing compiler for a quantum programming language&amp;rdquo;. Uses SBCL.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://tech.grammarly.com/blog/posts/Running-Lisp-in-Production.html&#34;&gt;&lt;strong&gt;Grammarly&lt;/strong&gt;&lt;/a&gt; is a famous English language writing-enhancement platform.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/grammarly.png&#34; alt=&#34;grammarly&#34; width=&#34;750&#34; style=&#34;z-index: 100&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.ravenpack.com/&#34;&gt;&lt;strong&gt;Ravenpack&lt;/strong&gt;&lt;/a&gt; is &amp;ldquo;the leading big data analytics provider for financial services&amp;rdquo;. &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7ldiyg/suggestion_for_common_lisp_internship/&#34;&gt;reddit announce&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/ravenpack.png&#34; alt=&#34;ravenpack&#34; width=&#34;750&#34; style=&#34;z-index: 100&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.itasoftware.com/&#34;&gt;&lt;strong&gt;ITA Software&lt;/strong&gt;&lt;/a&gt; is still Google&amp;rsquo;s
leading airfaire search and scheduling platform. They use SBCL, and
contribute to its development.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/ita.png&#34; alt=&#34;ita&#34; width=&#34;750&#34; style=&#34;z-index: 100&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.kinaknowledge.com/&#34;&gt;&lt;strong&gt;Kina knowledge&lt;/strong&gt;&lt;/a&gt; is a small company that &amp;ldquo;automates the processing of documents&amp;rdquo;: &amp;ldquo;We use Common Lisp extensively in our document processing software core for classification, extraction and other aspects of our service delivery and technology stack&amp;rdquo;. See their &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/lisp-interview-kina/&#34;&gt;Lisp Interview: questions to Alex Nygren&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://user-images.githubusercontent.com/3721004/138441191-375aa5dc-5a82-44e0-a175-61e97536cee6.png&#34; style=&#34;max-width: 750px&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Doremir Music Research AB&lt;/strong&gt; develops &lt;a href=&#34;https://scorecloud.com/&#34;&gt;ScoreCloud&lt;/a&gt;, a music notation software (a LispWorks product). It lets you play an instrument, sing or whistle into the app, and it writes the music score. Futuristic indeed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/scorecloud.png&#34; style=&#34;max-width: 750px&#34;/&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll stop here and I&amp;rsquo;ll let you discover the &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;&lt;strong&gt;awesome-lisp-companies&lt;/strong&gt;&lt;/a&gt; list!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lisp Interview: Arnold Noronha of Screenshotbot: from Facebook and Java to Common Lisp.</title>
      <link>/blog/lisp-interview-screenshotbot/</link>
      <pubDate>Mon, 06 Dec 2021 19:08:30 +0100</pubDate>
      
      <guid>/blog/lisp-interview-screenshotbot/</guid>
      <description>

&lt;p&gt;I have come to like asking questions to people running companies that
use CL, and I have Arnold in my radar for quite some time.&lt;/p&gt;

&lt;p&gt;He contributed a while back to my
&lt;a href=&#34;https://github.com/vindarel/cl-str/&#34;&gt;cl-str&lt;/a&gt; library, and at that
time, I don&amp;rsquo;t recall how many Lisp projects he had in his Github, but
not as much as today. Since then, he created
&lt;a href=&#34;https://screenshotbot.io/&#34;&gt;ScreenShotBot&lt;/a&gt; (an open-source screenshot
testing service) and he released a few very useful Lisp (and Elisp)
libraries. Wow! I&amp;rsquo;ll try to investigate what happened :)&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://screenshotbot.io/assets/images/integrations/botty.png&#34; alt=&#34;&#34; title=&#34;Screenshotbot&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;first-screenshotbot-it-s-an-open-source-project-and-a-company-its-website-shows-a-team-of-four-can-you-tell-us-what-s-the-state-of-the-project-of-the-company-what-are-your-goals-with-it-who-are-your-clients&#34;&gt;First, ScreenShotBot. It&amp;rsquo;s an open-source project and a company. Its website shows a team of four. Can you tell us what&amp;rsquo;s the state of the project, of the company, what are your goals with it? Who are your clients?&lt;/h2&gt;

&lt;p&gt;Sure. So the team of four isn&amp;rsquo;t fully active at the moment. We&amp;rsquo;re all
still friends, but Screenshotbot didn&amp;rsquo;t take off the way we wanted it
to, so currently it&amp;rsquo;s just me and Reuben.  I&amp;rsquo;m the primary developer,
Reuben &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; is actually my brother, he manages marketing. But he&amp;rsquo;s tech
savvy. I&amp;rsquo;ll talk about how he contributes in code without knowing any
Lisp in a second.&lt;/p&gt;

&lt;p&gt;Lili &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; and Francesco &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; are awesome designers we worked with in
building our marketing pages.&lt;/p&gt;

&lt;p&gt;Reuben and I are also prototyping some other ideas at the moment.&lt;/p&gt;

&lt;p&gt;By the way, I think cl-str was probably one of the first CL libraries I
contributed to. It&amp;rsquo;s also easily my most used library :)&lt;/p&gt;

&lt;h2 id=&#34;you-pinned-the-project-facebook-screenshot-tests-for-android-https-github-com-facebook-screenshot-tests-for-android-on-your-gh-profile-maybe-you-wrote-about-it-already-what-s-your-relation-with-this-project-we-read-you-built-the-infrastructure-for-running-screenshot-tests-at-facebook-which-still-runs-tests-from-ios-android-and-react-at-scale&#34;&gt;You pinned the project &lt;a href=&#34;https://github.com/facebook/screenshot-tests-for-android&#34;&gt;facebook/screenshot-tests-for-android&lt;/a&gt; on your GH profile. Maybe you wrote about it already. What&amp;rsquo;s your relation with this project? (we read you &amp;ldquo;built the infrastructure for running Screenshot Tests at Facebook, which still runs tests from iOS, Android and React at Scale.&amp;rdquo;)&lt;/h2&gt;

&lt;p&gt;I was the original author of that project when I worked at
Facebook. It&amp;rsquo;s the de-facto screenshot testing library for
Android. (The other one, called Shot, uses this library under the
hood.) It&amp;rsquo;s maintained by other engineers at Facebook at the moment.&lt;/p&gt;

&lt;p&gt;At Facebook, I also ended up building the infrastructure to run these
screenshot tests, and that infrastructure ended up being used for iOS
and React and ElectronJS etc. The infrastructure stored the
screenshots, bisected, sent tasks, notified on diff reviews etc.&lt;/p&gt;

&lt;p&gt;With Screenshotbot I wanted to build a similar infrastructure that can
be used outside of Facebook.&lt;/p&gt;

&lt;h2 id=&#34;so-do-you-come-from-facebook-and-from-java-ah-you-worked-at-google-too&#34;&gt;So… do you come from Facebook and from Java ? (ah, you worked at Google too!)&lt;/h2&gt;

&lt;p&gt;Yes Java! Also did C++ and lots of Python at Facebook.&lt;/p&gt;

&lt;h2 id=&#34;what-made-you-start-a-new-project-company-and&#34;&gt;What made you start a new project/company, and…&lt;/h2&gt;

&lt;p&gt;Speaking of Java.. Java is ridiculously slow to work with. Especially
on Android, every single change required you to re-build the entire
app. My initial goal when I started my own company was to solve this
problem. I wanted to build CL style interactive development for Java,
but without forcing developers to switch from Java. (Take a look at an
early demo here: &lt;a href=&#34;https://www.jipr.io/demo)&#34;&gt;https://www.jipr.io/demo)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I haven&amp;rsquo;t completely abandoned this project, I might get back to this
soon. But this is a good segue to your next question.&lt;/p&gt;

&lt;h2 id=&#34;the-famous-question-how-did-you-end-up-with-common-lisp&#34;&gt;(the famous question) how did you end up with Common Lisp?&lt;/h2&gt;

&lt;p&gt;So I&amp;rsquo;ve been toying with Lisp for a while. I started using StumpWM
around 2010, and have been using it ever since (I think I was looking
for Emacs level customizability for my WM which CL and StumpWM gave
me). My own personal website runs on CL, probably since about
2015. Using CL encouraged me to build small tools for personal use
without much friction. (For instance, I have my own weight tracker
tool, tracking my car mileage, tracking my investment portfolio etc.)
I just had my server running on my desktop, and Emacs was perpetually
connected to the Lisp server, so making changes would take less than a
minute.&lt;/p&gt;

&lt;p&gt;Even before I started using CL professionally, I attempted to build a
shitty Lisp interpreter way back in 2012 &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;. The goal here was mostly to
learn about compilers.&lt;/p&gt;

&lt;p&gt;Now, when I started working on Jipr, at some point I realized I needed
to define some kind of &amp;ldquo;bytecode&amp;rdquo;. But then I thought, why not just
use Lisp as the &amp;ldquo;bytecode&amp;rdquo;, i.e. the Java gets compiled to Lisp? I
needed a Lisp-like language that works with Android and Java to build
the actual Java interpreter. At that time, I could not find any CL
that provided me the ability, so I boldly took the Lisp that I built
in 2012, and actually built a shit tonne of real code on top of
it. (The demo I linked to earlier used my homegrown Lisp.)&lt;/p&gt;

&lt;p&gt;At some point, that stopped scaling. Every small change required lots
of debugging because of the lack of SLIME, and other debugging
tools. I gave up for a while, until one day I realized I could
actually pay LispWorks, and they have already built Android support
for me.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Paying for Lispworks was the best thing I&amp;rsquo;ve done in my startup
journey&lt;/em&gt;. Initially, I just wanted the Android support for building
Jipr, and I was able to remove all references of my homegrown Lisp
with a month of effort. Their support is spectacular. And having
access to Java libraries meant I could move a lot faster on my future
ideas, including Screenshotbot.&lt;/p&gt;

&lt;h2 id=&#34;are-you-the-only-lisp-developer-on-screenshotbot-did-you-have-to-make-a-colleague-work-on-the-lisp-codebase-and-how-did-that-go&#34;&gt;Are you the only (Lisp) developer on Screenshotbot, did you have to make a colleague work on the Lisp codebase and how did that go?&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m the solo Lisp developer. However: I&amp;rsquo;ve worked on multiple websites
collaborating with my wife (who has some experience with Python, but
not technical), and my brother (who is tech savvy, but not a
programmer). Both helped me build websites in a Lisp codebase because
of &lt;a href=&#34;https://github.com/moderninterpreters/markup&#34;&gt;Markup&lt;/a&gt;! &lt;em&gt;I helped them set up Atom + SLIMA&lt;/em&gt; (with SBCL, not
Lispworks since I couldn&amp;rsquo;t afford another license), &lt;em&gt;and then since it
looked like HTML from that point, they would mostly work with a theme
that we would purchase to build complex UIs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When they took over the UI, that left me more time to work on building
the core components and interactions for the apps.&lt;/p&gt;

&lt;h2 id=&#34;we-can-find-you-on-reddit-besides-it-is-there-another-lisp-circle-where-you-are-active-a-pro-mailing-list-do-you-have-interaction-with-the-pro-side-of-the-cl-community&#34;&gt;We can find you on reddit. Besides it, is there another Lisp circle where you are active? (a pro mailing list?) Do you have interaction with the &amp;ldquo;pro&amp;rdquo; side of the CL community?&lt;/h2&gt;

&lt;p&gt;Hmm, I&amp;rsquo;m definitely active on Reddit. I follow the LispWorks HUG, but
I&amp;rsquo;m not a super active participant. Do you have suggestions of where
else I should be active on?&lt;/p&gt;

&lt;h2 id=&#34;if-i-recall-correctly-you-use-lispworks-and-you-appreciate-its-java-ffi-can-you-give-details-on-your-stack-when-do-you-turn-to-the-java-side&#34;&gt;If I recall correctly, you use LispWorks, and you appreciate its Java FFI. Can you give details on your stack? When do you turn to the Java side?&lt;/h2&gt;

&lt;p&gt;I briefly described this above. For Jipr, which is literally a Java
interpreter, Java interop was a necessity (the interpreter which runs
in Lisp, keeps calling back and forth into Java). And it helps that
Lispworks also has Android support (which CCL and ABCL don&amp;rsquo;t have, the
other two implementations that support Java).&lt;/p&gt;

&lt;p&gt;For Screenshotbot, the app has multiple integrations with externals
tools such as Slack, Asana, etc. Sometimes, interacting with the
services&amp;rsquo; APIs aren&amp;rsquo;t that hard, and can be written in plain old
Lisp. But often, I need to prototype a solution quickly, and having
access to existing well-tested Java libraries are a necessity. (For
instance, I had a few sales calls where the client was using a
specific external tool for which I didn&amp;rsquo;t have the integration, and I
would have to work overnight to build the integration).&lt;/p&gt;

&lt;p&gt;Over-reliance on Java can eventually cause pain and suffering (I have
to restart the Lisp process if I make a Java change), so I avoid
writing any Java code, and instead talk to the Java libraries
directly, even if it&amp;rsquo;s slower. Usually these Java libraries are not in
the hot-path anyway, so performance isn&amp;rsquo;t critical. Occasionally I
rewrite code that relied on Java to just use plain CL.&lt;/p&gt;

&lt;h2 id=&#34;anymore-feedback-on-lispworks-it-seems-you-also-extensively-use-emacs-and-slime&#34;&gt;Anymore feedback on LispWorks? It seems you also extensively use Emacs and Slime.&lt;/h2&gt;

&lt;p&gt;Yeah, I definitely don&amp;rsquo;t use the LispWorks IDE. :) I tried it for a
while, but it wasn&amp;rsquo;t for me. Sly (I prefer Sly over Slime these days),
is definitely a more &amp;ldquo;complete&amp;rdquo; experience for me.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m the kind of hacker that is always optimizing their workflow. Emacs
just makes it way more easier to do that. &lt;a href=&#34;https://github.com/tdrhq/slite/&#34;&gt;Slite&lt;/a&gt; is obviously one
of my bigger examples, but there are always smaller things. (My most
recent one was automatically guessing which package to import a symbol
from, so I can press &lt;code&gt;C-c i&lt;/code&gt; on a symbol, and it&amp;rsquo;ll give me a list of
package candidates using &lt;code&gt;ido-completing-read&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Perhaps there are ways to do this with the LispWorks IDE, but I&amp;rsquo;m more
experienced with Emacs Lisp, and there&amp;rsquo;s a wealth of documentation and
blogs about how to do different things in Emacs.&lt;/p&gt;

&lt;h2 id=&#34;how-s-your-ci-and-deployment-story-going-is-everything-fine-is-there-anything-particular-to-cl&#34;&gt;How&amp;rsquo;s your CI and deployment story going, is everything fine, is there anything particular to CL?&lt;/h2&gt;

&lt;p&gt;I have a mono-repo. Almost all my Lisp code is in one single
repo. Some of my newer open source libraries get copied over from the
mono-repo to GitHub using Copybara.&lt;/p&gt;

&lt;p&gt;I run my own Jenkins server, but plan to switch to Buildbot. Jenkins
is annoying beyond a certain point. But it&amp;rsquo;s a great starting point
for anybody who doesn&amp;rsquo;t have CI.&lt;/p&gt;

&lt;p&gt;I have two desktops, and use my older desktop exclusively as a Jenkins
worker. But Lispworks adds a complication because of licensing issues,
so my primary desktop runs all the Lispworks jobs.&lt;/p&gt;

&lt;p&gt;Deployment is interesting. I heavily use bknr.datastore &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;, which while
awesome, adds a little pain point to deployment. Restarting a service
can take a 10-20s because we have to load all the objects to
memory. So I avoid restarting the service.&lt;/p&gt;

&lt;p&gt;Lispworks also adds a quirk. A deployed Lispworks image doesn&amp;rsquo;t have a
compiler, so I can&amp;rsquo;t just &lt;code&gt;git pull&lt;/code&gt; and &lt;code&gt;(asdf:load-system ...)&lt;/code&gt;. So
instead, from my desktop I build a bundled fasl file, and have scripts
to upload it to my server and have the server load the fasl file.&lt;/p&gt;

&lt;p&gt;Finally, bknr.datastore has some issues which reloading code, which
causes existing indices to become empty. I haven&amp;rsquo;t debugged why this
happens, but I&amp;rsquo;m close. I have workaround scripts for these that can
correct a bad index, but because of the potential of bringing my
datastore into a bad state, deployment is pretty manual at the moment.&lt;/p&gt;

&lt;h2 id=&#34;some-cl-libraries-you-particularly-like-some-you-wish-existed&#34;&gt;Some CL libraries you particularly like? Some you wish existed?&lt;/h2&gt;

&lt;p&gt;Apart from the usual suspects (cl-str, alexandria, cl-json,
hunchentoot etc):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;bknr.datastore: This is a game changer. If you&amp;rsquo;re the type of person
that likes prototyping things quickly, this is for you. If you need to
scale things, you can always do it when you have to. (In my experience,
not all ideas reach the stage where you need to scale over a 100
servers.) It does take a bit of getting used to (particularly dealing
with how to recover old snapshots, or replaying bad transactions). I&amp;rsquo;m using my own patches for Lispworks that aren&amp;rsquo;t merged upstream yet
(I have a PR for it). I think the index failing issue might be in my
own patches, but I don&amp;rsquo;t know for sure yet.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/dexador/&#34;&gt;dexador&lt;/a&gt; (as opposed to Drakma): For the longest time I avoided Dexador
because I thought Drakma is the more well established library. But
Drakma for all its history, still doesn&amp;rsquo;t handle SSL correctly at
least on LispWorks. And dexador does.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/qlot&#34;&gt;Qlot&lt;/a&gt; also sounds awesome, and I want to start using it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some I wish existed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A carefully designed algorithms library, with all the common
algorithms, and consistent APIs.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&amp;hellip;in particular graph algorithms. There are libraries out there, and
I have used them, but they are clunky and not very well documented.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Better image processing libraries. Opticl is fine, but confusing to
work with. Maybe it&amp;rsquo;s just me.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A modern and complete Selenium library. I use the Java library with
the Java FFI.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;An extensible test matchers library, similar to Java&amp;rsquo;s
Hamcrest. There&amp;rsquo;s a cl-hamcrest, but it&amp;rsquo;s not very extensible, and you
can&amp;rsquo;t configure the test result output IIRC. I attempted a solution
here (copied over as part of my mono-repo):
&lt;a href=&#34;https://github.com/screenshotbot/screenshotbot-oss/tree/main/src/fiveam-matchers&#34;&gt;https://github.com/screenshotbot/screenshotbot-oss/tree/main/src/fiveam-matchers&lt;/a&gt;,
but it&amp;rsquo;s not ready for publishing yet.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also think there&amp;rsquo;s a verbosity problem to be solved with classes and
methods, that still needs to be solved in the Lispy way. For instance,
in Java or python, the method names don&amp;rsquo;t have to be explicitly
imported, but in CL we have to import each method that we need to use,
which makes it hard to define what the object&amp;rsquo;s &amp;ldquo;interface&amp;rdquo; is. I am
not proposing a solution here, I&amp;rsquo;m just identifying this as a problem
that slows me down.&lt;/p&gt;

&lt;h2 id=&#34;is-that-a-baby-alligator-you-caught-yourself-on-your-gh-profile-picture&#34;&gt;Is that a baby alligator you caught yourself on your GH profile picture?&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s one of those pictures they take of you at a tourist trap alligator tour. :)&lt;/p&gt;

&lt;p&gt;The alligator&amp;rsquo;s jaw is taped shut.&lt;/p&gt;

&lt;h2 id=&#34;anything-more-to-add&#34;&gt;Anything more to add?&lt;/h2&gt;

&lt;p&gt;Nothing I can think of :)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Thanks and the best for your projects!&lt;/p&gt;

&lt;p&gt;notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arnold&amp;rsquo;s GitHub: &lt;a href=&#34;https://github.com/tdrhq/&#34;&gt;https://github.com/tdrhq/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ModernInterpreters: &lt;a href=&#34;https://github.com/moderninterpreters&#34;&gt;https://github.com/moderninterpreters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;&lt;a href=&#34;https://www.linkedin.com/in/reuben-noronha/?miniProfileUrn=urn%3Ali%3Afs_miniProfile%3AACoAAAsEnhABsKiB51XHsvofsDRNmKm8mKEaxOg&#34;&gt;https://www.linkedin.com/in/reuben-noronha/?miniProfileUrn=urn%3Ali%3Afs_miniProfile%3AACoAAAsEnhABsKiB51XHsvofsDRNmKm8mKEaxOg&lt;/a&gt;
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:1&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;&lt;a href=&#34;https://www.linkedin.com/search/results/all/?keywords=lilibeth%20bustos%20linares&amp;amp;origin=RICH_QUERY_SUGGESTION&amp;amp;position=0&amp;amp;searchId=11575c64-025c-46c3-b812-c8f19e298680&amp;amp;sid=ZY7&#34;&gt;https://www.linkedin.com/search/results/all/?keywords=lilibeth%20bustos%20linares&amp;amp;origin=RICH_QUERY_SUGGESTION&amp;amp;position=0&amp;amp;searchId=11575c64-025c-46c3-b812-c8f19e298680&amp;amp;sid=ZY7&lt;/a&gt;
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:2&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;&lt;a href=&#34;https://www.linkedin.com/in/francescostumpo/&#34;&gt;https://www.linkedin.com/in/francescostumpo/&lt;/a&gt;
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:3&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;&lt;a href=&#34;https://github.com/tdrhq/mini-lisp&#34;&gt;https://github.com/tdrhq/mini-lisp&lt;/a&gt;
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:4&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;an object-persistence library with transactions for CL: &lt;a href=&#34;https://github.com/hanshuebner/bknr-datastore/&#34;&gt;https://github.com/hanshuebner/bknr-datastore/&lt;/a&gt; See also this &lt;a href=&#34;https://ashok-khanna.medium.com/persistent-in-memory-data-storage-in-common-lisp-b-k-n-r-37f8ae76042f&#34;&gt;good tutorial on Medium&lt;/a&gt;.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:6&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Lisp for the web: pagination and cleaning up HTML with LQuery</title>
      <link>/blog/lisp-for-the-web-pagination-and-cleaning-up-html/</link>
      <pubDate>Thu, 25 Nov 2021 11:39:18 +0100</pubDate>
      
      <guid>/blog/lisp-for-the-web-pagination-and-cleaning-up-html/</guid>
      <description>

&lt;p&gt;I maintain a web application written in Common Lisp, used by real
world© clients© (incredible I know), and I finally got to finish two
little additions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add &lt;strong&gt;pagination&lt;/strong&gt; to the list of products&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cleanup the HTML&lt;/strong&gt; I get from webscraping (so we finally fetch a book
summary, how cool) (for those who pay for it, we can also use a
third-party book database).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The HTML cleanup part is about how to use &lt;a href=&#34;https://github.com/Shinmera/lquery/&#34;&gt;LQuery&lt;/a&gt; for
the task. Its doc shows the &lt;code&gt;remove&lt;/code&gt; function from the beginning, but I have had difficulty to find how to use it. Here&amp;rsquo;s how. (see &lt;a href=&#34;https://github.com/Shinmera/lquery/issues/11&#34;&gt;issue #11&lt;/a&gt;)&lt;/p&gt;

&lt;h2 id=&#34;cleanup-html-with-lquery&#34;&gt;Cleanup HTML with lquery&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://shinmera.github.io/lquery/&#34;&gt;https://shinmera.github.io/lquery/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LQuery has &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;remove-attr&lt;/code&gt;, &lt;code&gt;remove-class&lt;/code&gt;, &lt;code&gt;remove-data&lt;/code&gt;. It seems pretty capable.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s say I got some HTML and I parsed it with LQuery. There are two buttons I would like to remove (you know, the &amp;ldquo;read more&amp;rdquo; and &amp;ldquo;close&amp;rdquo; buttons that are inside the book summary):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$ *node* &amp;quot;.description&amp;quot; (serialize))
   ;; HTML content…
        &amp;lt;button type=\&amp;quot;button\&amp;quot; class=\&amp;quot;description-btn js-descriptionOpen\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;mr-005\&amp;quot;&amp;gt;Lire la suite&amp;lt;/span&amp;gt;&amp;lt;i class=\&amp;quot;far fa-chevron-down\&amp;quot; aria-hidden=\&amp;quot;true\&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;
        &amp;lt;button type=\&amp;quot;button\&amp;quot; class=\&amp;quot;description-btn js-descriptionClose\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;mr-005\&amp;quot;&amp;gt;Fermer&amp;lt;/span&amp;gt;&amp;lt;i class=\&amp;quot;far fa-chevron-up\&amp;quot; aria-hidden=\&amp;quot;true\&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On GitHub, @shinmera tells us we can simply do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;($ *node* &amp;quot;.description&amp;quot; (remove &amp;quot;button&amp;quot;) (serialize))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Unfortunately, I try and I still see the two buttons in the node or in the output. What worked for me is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first I check that I can access these HTML nodes with a CSS selector:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$ *NODE* &amp;quot;.description button&amp;quot; (serialize))
;; =&amp;gt; output
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;now I use &lt;code&gt;remove&lt;/code&gt;. This returns the removed elements on the REPL, but they are corrcetly removed from the node (a global var passed as parameter):&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$ *NODE* &amp;quot;.description button&amp;quot; (remove) (serialize))
;; #(&amp;quot;&amp;lt;button type=\&amp;quot;button\&amp;quot; class=\&amp;quot;description-btn js-descriptionOpen\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;mr-005\&amp;quot;&amp;gt;Lire la suite&amp;lt;/span&amp;gt;&amp;lt;i class=\&amp;quot;far fa-chevron-down\&amp;quot; aria-hidden=\&amp;quot;true\&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if I check the description field:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$ *NODE* &amp;quot;.description&amp;quot; (serialize))
;; …
;; &amp;lt;/p&amp;gt;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I have no more buttons \o/&lt;/p&gt;

&lt;p&gt;Now to pagination.&lt;/p&gt;

&lt;h2 id=&#34;pagination&#34;&gt;Pagination&lt;/h2&gt;

&lt;p&gt;This is my 2c, hopefully this will help someone do the same thing quicker, and hopefully we&amp;rsquo;ll abstract this in a library…&lt;/p&gt;

&lt;p&gt;On my web app I display a list of products (books). We have a search
box with a select input in order to filter by shelf (category). If no
shelf was chosen, we displayed only the last 200 most recent books. No
need of pagination, yet… There were only a few thousand books in
total, so we could show a shelf entirely, it was a few hundred books
by shelf maximum. But the bookshops grow and my app crashed once
(thanks, Sentry and cl-sentry). Here&amp;rsquo;s how I added pagination. You can
find the code
&lt;a href=&#34;https://gitlab.com/vindarel/abstock/-/blob/master/src/pagination.lisp&#34;&gt;here&lt;/a&gt;
and the &lt;a href=&#34;https://mmontone.github.io/djula/&#34;&gt;Djula&lt;/a&gt; template
&lt;a href=&#34;https://gitlab.com/vindarel/abstock/-/blob/master/src/templates/includes/pagination.html&#34;&gt;there&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The goal is to get this and if possible, in a re-usable way:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/pagination.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;I simply create a dict object with required data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the current page number&lt;/li&gt;
&lt;li&gt;the page size&lt;/li&gt;
&lt;li&gt;the total number of elements&lt;/li&gt;
&lt;li&gt;the max number of buttons we want to display&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun make-pagination (&amp;amp;key (page 1) (nb-elements 0) (page-size 200)
                         (max-nb-buttons 5))
  &amp;quot;From a current page number, a total number of elements, a page size,
  return a dict with all of that, and the total number of pages.

  Example:

(get-pagination :nb-elements 1001)
;; =&amp;gt;
 (dict
  :PAGE 1
  :NB-ELEMENTS 1001
  :PAGE-SIZE 200
  :NB-PAGES 6
  :TEXT-LABEL \&amp;quot;Page 1 / 6\&amp;quot;
 )
&amp;quot;
  (let* ((nb-pages (get-nb-pages nb-elements page-size))
         (max-nb-buttons (min nb-pages max-nb-buttons)))
    (serapeum:dict :page page
                   :nb-elements nb-elements
                   :page-size page-size
                   :nb-pages nb-pages
                   :max-nb-buttons max-nb-buttons
                   :text-label (format nil &amp;quot;Page ~a / ~a&amp;quot; page nb-pages))))

(defun get-nb-pages (length page-size)
  &amp;quot;Given a total number of elements and a page size, compute how many pages fit in there.
  (if there&#39;s a remainder, add 1 page)&amp;quot;
  (multiple-value-bind (nb-pages remainder)
      (floor length page-size)
    (if (plusp remainder)
        (1+ nb-pages)
        nb-pages)))
#+(or)
(assert (and (= 30 (get-nb-pages 6000 200))
             (= 31 (get-nb-pages 6003 200))
             (= 1 (get-nb-pages 1 200))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You call it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-pagination :page page
    :page-size *page-length*
    :nb-elements (length results))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then pass it to your template, which can &lt;code&gt;{% include %}&lt;/code&gt; the template
given above, which will create the buttons (we use Bulma CSS there).&lt;/p&gt;

&lt;p&gt;When you click a button, the new page number is given as a GET parameter. You must catch it in your route definition, for example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(easy-routes:defroute search-route (&amp;quot;/search&amp;quot; :method :get) (q shelf page)
   …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, I updated my web app (while it runs, it&amp;rsquo;s more fun and why shut it down? It&amp;rsquo;s been 2 years I do this and so far all goes well (I try to not upgrade the Quicklisp dist though, it went badly once, because of external, system-wide dependencies)) (see this &lt;a href=&#34;https://github.com/vindarel/demo-web-live-reload&#34;&gt;demo-web-live-reload&lt;/a&gt;).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;That&amp;rsquo;s exactly the sort of things that should be extracted in a
library, so we can focus on our application, not on trivial things. I
started that work, but I&amp;rsquo;ll spend more time next time I need it…  call it
&amp;ldquo;needs driven development&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Happy lisping.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lisp Interview: questions to  Alex Nygren of Kina Knowledge, using Common Lisp extensively in their document processing stack</title>
      <link>/blog/lisp-interview-kina/</link>
      <pubDate>Fri, 22 Oct 2021 12:49:17 +0200</pubDate>
      
      <guid>/blog/lisp-interview-kina/</guid>
      <description>

&lt;p&gt;Recently, the
&lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies/&#34;&gt;awesome-lisp-companies&lt;/a&gt;
list was posted on HN, more people got to know it (look, this list is
fan-cooked and we add companies when we learn about one, often by
chance, don&amp;rsquo;t assume it&amp;rsquo;s anything &amp;ldquo;official&amp;rdquo; or exhaustive), and Alex
Nygren informed us that his company &lt;a href=&#34;https://www.kinaknowledge.com/&#34;&gt;Kina
Knowledge&lt;/a&gt; uses Common Lisp in
production:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We use Common Lisp extensively in our document processing software core for classification, extraction and other aspects of our service delivery and technology stack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He very kindly answered more questions.&lt;/p&gt;

&lt;h2 id=&#34;thanks-for-letting-us-know-about-kina-knowledge-a-few-more-words-if-you-have-time-what-implementation-s-are-you-using&#34;&gt;Thanks for letting us know about Kina Knowledge. A few more words if you have time? What implementation(s) are you using?&lt;/h2&gt;

&lt;p&gt;We use &lt;strong&gt;SBCL&lt;/strong&gt; for all our Common Lisp processes.  It&amp;rsquo;s easier with the
standardization on a single engine, but we also have gotten tied to it
in some of our code base due to using the built in SBCL specific
extensions.  I would like, but have no bandwidth, to evaluate CCL as
well, especially on the Windows platform, where SBCL is weakest.
Since our clients use Windows systems attached to scanners, we need to
be able to support it with a client runtime.&lt;/p&gt;

&lt;p&gt;Development is on MacOS with Emacs or Ubuntu with Emacs for CL, and
then JetBrains IDEs for Ruby and JS and Visual Studio for some
interface code to SAP and such.  &lt;strong&gt;We develop the Kina UI in Kina itself
using our internal Lisp, which provides a similar experience to
Emacs/SLY&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&#34;what-is-not-lisp-in-your-stack-for-example-in-kina-extracts-information-from-pdf-tiffs-excel-word-and-more-as-we-read-on-your-website&#34;&gt;What is not Lisp in your stack? For example, in &amp;ldquo;Kina extracts information from PDF, TIFFs, Excel, Word and more&amp;rdquo; as we read on your website.&lt;/h2&gt;

&lt;p&gt;Presently we use a Rails/Ruby environment for driving our JSON based
API, and some legacy web functions.  However, increasingly, once the
user is logged in, they are interacting with a Common Lisp back end
via a web socket (Hunchentoot and Hunchensocket) interacting with a
Lisp based front end.  Depending on the type of information
extraction, the system uses Javascript, Ruby and Common Lisp.
Ideally, I&amp;rsquo;d like to get all the code refactored into a prefix
notation, targeting Common Lisp or &lt;strong&gt;DLisp&lt;/strong&gt; (what we call our internal
Lisp that compiles into Javascript).&lt;/p&gt;

&lt;h2 id=&#34;what-s-your-position-on-open-source-do-you-use-open-source-lisp-libraries-do-you-plan-to-open-source-some&#34;&gt;What&amp;rsquo;s your position on open-source: do you use open-source Lisp libraries, do you (plan to) open-source some?&lt;/h2&gt;

&lt;p&gt;Yes.  We recently put our JSON-LIB
(&lt;a href=&#34;https://github.com/KinaKnowledge/json-lib&#34;&gt;https://github.com/KinaKnowledge/json-lib&lt;/a&gt;) out on Github, which is
our internal JSON parser and encoder and &lt;strong&gt;we want to open source
DLisp&lt;/strong&gt; after some clean-up work.  Architecturally, DLisp can run in
the browser, or in sandboxed Deno containers on the server side, so we
can reuse libraries easily.  It&amp;rsquo;s not dependent on a server-side
component though to run.&lt;/p&gt;

&lt;p&gt;Library wise, we strictly try and limit how many third party
(especially from the NPM ecosystem) libraries we are dependent on,
especially in the Javascript world.  In CL, we use the standard stuff
like Alexandria, Hunchentoot, Bordeaux Threads, and things like zip.&lt;/p&gt;

&lt;h2 id=&#34;how-did-hiring-and-forming-lisp-or-non-lisp-developers-go-did-you-look-for-experienced-lispers-or-did-you-seek-experienced-engineers-even-with-little-to-no-prior-lisp-background&#34;&gt;How did hiring and forming lisp or non-lisp developers go? Did you look for experienced lispers or did you seek experienced engineers, even with little to no prior Lisp background?&lt;/h2&gt;

&lt;p&gt;Because we operate a lot in Latin America, &lt;strong&gt;I trained non-lisper
engineers&lt;/strong&gt; who speak Spanish on how to program Lisp, specifically our
DLisp, since most customizations occur specifically for user interface
and workflows around document centric processes, such as presenting
linked documents and their data in specific ways.  How the lisp way of
thinking really depended on their aptitude with programming, and their
English capabilities to understand me and the system.  The user system
is multilingual, but the development documentation is all in English.
But it was really amazing when I saw folks who are experienced with
Javascript and .Net get the ideas of Lisp and how compositional it can
be as you build up towards a goal.&lt;/p&gt;

&lt;p&gt;Besides, &lt;strong&gt;with DLisp, you can on the fly construct a totally new UI
interaction - live - in minutes and see changes in the running app&lt;/strong&gt;
without the dreadful recompile-and-reload everything cycle that is
typical.  Instead, just recompile the function (analogous to C-c, C-c
in Emacs), in the browser, and see the change.  Then these guys would
go out and interact with clients and build stuff.  I knew once I saw
Spanish functions and little DSLs showing up in organizational
instances that they were able to make progress.  I think it is a good
way to introduce people to Lisp concepts without having to deal with
the overhead of learning Emacs at the same time.  I pushed myself
through that experience when I first was learning CL, and now use
Emacs every day for a TON of work tasks, but at the beginning it was
tough, and I had to intentionally practice getting to the muscle
memory that is required to be truly productive in a tool.&lt;/p&gt;

&lt;h2 id=&#34;how-many-lispers-are-working-together-how-big-a-codebase-do-you-manage&#34;&gt;How many lispers are working together, how big a codebase do you manage?&lt;/h2&gt;

&lt;p&gt;Right now, in our core company we have three people, two here in
Virginia and one in Mexico City.  We use partners that provide
services such as scanning and client integration work.  &lt;strong&gt;We are
self-funded and have grown organically&lt;/strong&gt;, which is freeing because we
are not beholden to investor needs.  We maintain maximum flexibility,
at the expense of capital.  Which is OK for us right now.  &lt;strong&gt;Lisp allows
us to scale dramatically and manage a large code base.&lt;/strong&gt;  I haven&amp;rsquo;t line
counted recently, but it exceeds 100K lines across server and client,
with &amp;gt; 50% in Lisp.&lt;/p&gt;

&lt;h2 id=&#34;do-you-sometimes-wish-the-cl-pro-world-was-more-structured-we-have-a-cl-foundation-but-not-so-much-active&#34;&gt;Do you sometimes wish the CL (pro) world was more structured? (we have a CL Foundation but not so much active).&lt;/h2&gt;

&lt;p&gt;I really like the Common Lisp world.  &lt;strong&gt;I would like it to be more
popular, but at the same time, it is a differentiator for us&lt;/strong&gt;.  It is
fast - our spatial classifier takes only milliseconds to come to a
conclusion about a page (there is additional time prior to this step
due to the OpenCV processing - but not too much) and identify it and
doesn&amp;rsquo;t require expensive hardware.  Most of our instances run on
ARM-64, which at least at AWS, is 30% or so cheaper than x86-64.  The
s-expression structures align to document structures nicely and allow
a nice representation that doesn&amp;rsquo;t lose fidelity to the original
layouts and hierarchies.  I am not as active as I would like to be in
the Common Lisp community, mainly due to time and other commitments.
I don&amp;rsquo;t know much about the CL foundation.&lt;/p&gt;

&lt;h2 id=&#34;and-so-how-did-you-end-up-with-cl&#34;&gt;And so, how did you end up with CL?&lt;/h2&gt;

&lt;p&gt;Our UI was first with the DLisp concepts.  I was &lt;strong&gt;intrigued by Clojure&lt;/strong&gt;
for the server portion, but I couldn&amp;rsquo;t come to terms with the JVM and
the heavyweight of it.  The server-side application was outgrowing the
Rails architecture in terms of what we wanted to do with it, and, at
the time, 4 years ago, Ruby was slower.  In fact, Ruby had become a
processing bottleneck for us (though I am certain the code could have
been improved too).  I liked the idea of distributing binary
applications as well, which we needed to do in some instances, and
building a binary runtime of the software was a great draw, too.&lt;/p&gt;

&lt;p&gt;I also liked how well CL is thought out, from a spec standpoint.  It
is stable both in terms of performance and change.  I had been
building components with TensorFlow and Python 3, but for what I
wanted to do, I couldn&amp;rsquo;t see how I could get there with back
propagation and the traditional &amp;ldquo;lets calculate the entire network
state&amp;rdquo;.  If you don&amp;rsquo;t have access to high end graphic cards, it&amp;rsquo;s just
too slow and too heavy.  I was able to get what we needed to do in CL
after several iterations and dramatically improve speed and resource
utilization.  I am very happy with that outcome.  We are in what I
consider to be a hard problem space: we take analog representations of
information, a lot of it being poor quality and convert it to clean,
structured digital information.  CL is the core of that for us.&lt;/p&gt;

&lt;p&gt;Here is an example of our UI, where extractions and classification can
be managed.  This is described in DLisp which interacts with a Common
Lisp back end via a web socket.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://user-images.githubusercontent.com/3721004/138441231-44c75ef7-4a0d-4735-8f4e-2226760b2acb.png&#34; style=&#34;max-width: 1000px&#34;/&gt;&lt;/p&gt;

&lt;p&gt;Here is the function for the above view being edited in Kina itself.
We do not obfuscate our client code, and all code that runs on our
clients&amp;rsquo; computers is fully available to view and, with the right
privileges, to modify and customize.  You can see the Extract
Instruction Language in the center pane, which takes ideas from the
Logo language in terms of a cursor (aka the turtle) that can be moved
around relative to the document.  We build this software to be used by
operations teams and having a description language that is
understandable by non-programmers such as auditors and operations
personnel, is very useful.  You can redefine aspects of the view or
running environment and the change can take effect on the fly.  Beyond
the Javascript boot scaffolding to get the system started up in the
browser, everything is DLisp communicating with Common Lisp and,
depending on the operation, Rails.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://user-images.githubusercontent.com/3721004/138441191-375aa5dc-5a82-44e0-a175-61e97536cee6.png&#34; style=&#34;max-width: 1000px&#34;/&gt;&lt;/p&gt;

&lt;p&gt;I hope this information is helpful!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;It is, thanks again!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Discovering the Lispworks IDE</title>
      <link>/blog/discovering-the-lispworks-ide/</link>
      <pubDate>Mon, 24 May 2021 13:57:41 +0200</pubDate>
      
      <guid>/blog/discovering-the-lispworks-ide/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;http://www.lispworks.com/&#34;&gt;LispWorks&lt;/a&gt; is a Common Lisp implementation
that comes with its own Integrated Development Environment (IDE) and
its share of unique features, such as the CAPI GUI toolkit.  It is
&lt;strong&gt;proprietary&lt;/strong&gt; and provides a &lt;strong&gt;free limited version&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here, we will mainly explore its IDE, asking ourselves what it can
offer to a seasoned lisper used to Emacs and Slime. The short answer
is: more graphical tools, such as an easy to use graphical stepper, a
tracer, a code coverage browser or again a class browser. Setting and
using breakpoints was easier than on Slime.&lt;/p&gt;

&lt;p&gt;LispWorks also provides more integrated tools (the Process browser
lists all processes running in the Lisp image and we can
stop, break or debug them) and presents many information in the form of
graphs (for example, a graph of function calls or a graph of all the
created windows).&lt;/p&gt;

&lt;div class=&#34;info-box info&#34;&gt;
&lt;!-- if inside a &lt;p&gt; then bootstrap adds 10px padding to the bottom --&gt;
&lt;strong&gt;Note:&lt;/strong&gt; you will find updated versions of this review on the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;Cookbook&lt;/a&gt;.
&lt;/div&gt;

&lt;p&gt;&lt;img src=&#34;/images/lispworks/two-sided-view.png&#34; width=&#34;700&#34; alt=&#34;LispWorks&#39; listener and editor in the Mate desktop environment&#34;/&gt;&lt;/p&gt;

&lt;h2 id=&#34;lispworks-features&#34;&gt;LispWorks features&lt;/h2&gt;

&lt;p&gt;We can see a matrix of LispWorks features by edition and platform here: &lt;a href=&#34;http://www.lispworks.com/products/features.html&#34;&gt;http://www.lispworks.com/products/features.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We highlight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;32-bit, 64-bit and ARM support on Windows, MacOS, Linux, Solaris, FreeBSD,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/lw61/CAPRM/html/capiref.htm&#34;&gt;CAPI portable GUI toolkit&lt;/a&gt;: provides native look-and-feel on Windows, Cocoa, GTK+ and Motif.

&lt;ul&gt;
&lt;li&gt;comes with a graphical &amp;ldquo;Interface Builder&amp;rdquo; (think QtCreator) (though not available on MacOS (nor on mobile))&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/products/lw4mr.html&#34;&gt;LispWorks for mobile runtime&lt;/a&gt;, for Android and iOS,&lt;/li&gt;
&lt;li&gt;optimized application delivery: LispWorks can use a tree shaker to
remove unused lisp code from the delivered applicatiion, thus
shipping lighter binaries than existing open-source implementations.&lt;/li&gt;
&lt;li&gt;ability to deliver a dynamic library,&lt;/li&gt;
&lt;li&gt;a &lt;a href=&#34;http://www.lispworks.com/documentation/lw71/LW/html/lw-113.htm&#34;&gt;Java interface&lt;/a&gt;, allowing to call from Lisp to Java or the other way around,&lt;/li&gt;
&lt;li&gt;an Objective-C and Cocoa interface, with drag and drop and multi-touch support,&lt;/li&gt;
&lt;li&gt;a Foreign Language Interface,&lt;/li&gt;
&lt;li&gt;TCP/UDP sockets with SSL &amp;amp; IPv6 support,&lt;/li&gt;
&lt;li&gt;natived threads and symmetric multiprocessing, unicode support, and all other Common Lisp features, and all other LispWorks Enterprise features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, of course, a built-in IDE.&lt;/p&gt;

&lt;p&gt;LispWorks is used in diverse areas of the industry. They maintain &lt;a href=&#34;http://www.lispworks.com/success-stories/index.html&#34;&gt;a list of success stories&lt;/a&gt;. As for software that we can use ourselves, we find &lt;a href=&#34;https://scorecloud.com/&#34;&gt;ScoreCloud&lt;/a&gt; amazing (a music notation software: you play an instrument, sing or whistle and it writes the music) or &lt;a href=&#34;https://github.com/openmusic-project/openmusic/&#34;&gt;OpenMusic&lt;/a&gt; (opensource composition environment).&lt;/p&gt;

&lt;h3 id=&#34;free-edition-limitations&#34;&gt;Free edition limitations&lt;/h3&gt;

&lt;p&gt;The download instructions and the limitations are given &lt;a href=&#34;http://www.lispworks.com/downloads/index.html&#34;&gt;on the download page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The limitations are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a &lt;strong&gt;heap size limit&lt;/strong&gt; which, if exceeded, causes the image to exit. A warning is provided when the limit is approached.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does it prevent us to do? As an illustration, we can not load this set of libraries together in the same image:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &#39;(&amp;quot;alexandria&amp;quot; &amp;quot;serapeum&amp;quot; &amp;quot;bordeaux-threads&amp;quot; &amp;quot;lparallel&amp;quot; &amp;quot;dexador&amp;quot; &amp;quot;hunchentoot&amp;quot; &amp;quot;quri&amp;quot; &amp;quot;ltk&amp;quot; &amp;quot;cl-ppcre&amp;quot; &amp;quot;mito&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There is a &lt;strong&gt;time limit of 5 hours&lt;/strong&gt; for each session, after which LispWorks Personal exits, possibly without saving your work or performing cleanups such as removing temporary files. You are warned after 4 hours of use.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;It is &lt;strong&gt;impossible to build a binary&lt;/strong&gt;. Indeed, the functions &lt;a href=&#34;http://www.lispworks.com/documentation/lw71/LW/html/lw-95.htm&#34;&gt;save-image&lt;/a&gt;, &lt;a href=&#34;http://www.lispworks.com/documentation/lw71/DV/html/delivery-4.htm#pgfId-852223&#34;&gt;deliver&lt;/a&gt; (&lt;em&gt;the&lt;/em&gt; function to create a stand-alone executable), and load-all-patches are not available.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initialization files are not loaded&lt;/strong&gt;. If you are used to initializing Quicklisp from your &lt;code&gt;~/.sbclrc&lt;/code&gt; on Emacs, you&amp;rsquo;ll have to load an init file manually every time you start LispWorks (&lt;code&gt;(load #p&amp;quot;~/.your-init-file&lt;/code&gt;)).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the record, the snippet provided by Quicklisp to put in one&amp;rsquo;s startup file is the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; provided you installed quicklisp in ~/quicklisp/
(let ((quicklisp-init (merge-pathnames &amp;quot;quicklisp/setup.lisp&amp;quot; (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&amp;rsquo;ll have to paste it to the listener window (with the &lt;code&gt;C-y&lt;/code&gt; key, y as &amp;ldquo;yank&amp;rdquo;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layered products that are part of LispWorks Professional and Enterprise Editions (CLIM, KnowledgeWorks, Common SQL and LispWorks ORB) are not included. But &lt;strong&gt;we can try the CAPI toolkit&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The installation process requires you to fill an HTML form to receive
a download link, then to run a first script that makes you accept the
terms and the licence, then to run a second script that installs the software.&lt;/p&gt;

&lt;h3 id=&#34;licencing-model&#34;&gt;Licencing model&lt;/h3&gt;

&lt;p&gt;LispWorks actually comes in four paid editions. It&amp;rsquo;s all explained by themselves here: &lt;a href=&#34;http://www.lispworks.com/products/lispworks.html&#34;&gt;http://www.lispworks.com/products/lispworks.html&lt;/a&gt;. In short, there is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Hobbyist edition with &lt;code&gt;save-image&lt;/code&gt; and &lt;code&gt;load-all-patches&lt;/code&gt;, to apply updates of minor versions, without the obvious limitations, for non-commercial and non-academic use,&lt;/li&gt;
&lt;li&gt;a HobbyistDV edition with the &lt;code&gt;deliver&lt;/code&gt; function to create executables (still for non-commercial and non-academic uses),&lt;/li&gt;
&lt;li&gt;a Professional edition, with the &lt;code&gt;deliver&lt;/code&gt; function, for commercial and academic uses,&lt;/li&gt;
&lt;li&gt;an Enterprise one, with their enterprise modules: the Common SQL interface, LispWorks ORB, KnowledgeWorks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time of writing, the licence of the hobbyist edition costs 750 USD, the pro version the double. They are bought for a LW version, per platform. They have no limit of time.&lt;/p&gt;

&lt;div class=&#34;info-box info&#34;&gt;
&lt;!-- if inside a &lt;p&gt; then bootstrap adds 10px padding to the bottom --&gt;
&lt;strong&gt;NB:&lt;/strong&gt; Please double check their upstream resources and don&#39;t hesitate to contact them.
&lt;/div&gt;

&lt;h2 id=&#34;lispworks-ide&#34;&gt;LispWorks IDE&lt;/h2&gt;

&lt;p&gt;The LispWorks IDE is self-contained, but it is also possible to use LispWorks-the-implementation from Emacs and Slime (see below).&lt;/p&gt;

&lt;h3 id=&#34;the-editor&#34;&gt;The editor&lt;/h3&gt;

&lt;p&gt;The editor offers what&amp;rsquo;s expected: a TAB-completion pop-up, syntax
highlighting, Emacs-like keybindings (including the &lt;code&gt;M-x&lt;/code&gt; extended
command). The menus help the discovery.&lt;/p&gt;

&lt;p&gt;We personally found the editing experience a bit &amp;ldquo;raw&amp;rdquo;. For example:
- indention after a new line is not automatic, one has to press TAB
again.
- the auto-completion is not fuzzy.
- there are no plugins similar to Paredit or Lispy, nor a Vim layer.&lt;/p&gt;

&lt;p&gt;We also had an issue, in that the go-to-source function bound to &lt;code&gt;M-.&lt;/code&gt;
did not work out for built-in Lisp symbols. This is probably a free
edition limitation too.&lt;/p&gt;

&lt;p&gt;The editor provides an interesting tab: Changed Definitions. It lists the functions and methods that were redefined since, at our choosing: the first edit of the session, the last save, the last compile.&lt;/p&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;a href=&#34;http://www.lispworks.com/documentation/lw71/EDUG-U/html/eduser-u.htm&#34;&gt;Editor User Guide&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;keybindings&#34;&gt;Keybindings&lt;/h3&gt;

&lt;p&gt;Most of the keybindings are similar to Emacs, but not all. Here are some differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to &lt;strong&gt;compile a function&lt;/strong&gt;, use &lt;code&gt;C-S-c&lt;/code&gt; (control, shift and c), instead of C-c C-c.&lt;/li&gt;
&lt;li&gt;to &lt;strong&gt;compile the current buffer&lt;/strong&gt;, use &lt;code&gt;C-S-b&lt;/code&gt; (instead of C-c C-k).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similar ones include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;C-g&lt;/code&gt; to cancel what you&amp;rsquo;re doing,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-x C-s&lt;/code&gt; to save the current buffer,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-w&lt;/code&gt; and &lt;code&gt;C-y&lt;/code&gt; to copy and paste,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-b&lt;/code&gt;, &lt;code&gt;M-f&lt;/code&gt;, &lt;code&gt;C-a&lt;/code&gt;, &lt;code&gt;C-e&lt;/code&gt;… to move around words, to go to the beginning or the end of the line,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-k&lt;/code&gt; to kill until the end of the line, &lt;code&gt;C-w&lt;/code&gt; to kill a selected region,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-.&lt;/code&gt; to find the source of a symbol,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-x C-e&lt;/code&gt; to evaluate the current defun,&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some useful functions don&amp;rsquo;t have a keybinding by default, for example:&lt;/p&gt;

&lt;!-- - delete selected text with `M-x delete-region` (or kill the region with `C-w`) --&gt;

&lt;ul&gt;
&lt;li&gt;clear the REPL with &lt;code&gt;M-x Clear Listener&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Backward Kill Line&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is possible to use &lt;strong&gt;classical keybindings&lt;/strong&gt;, à la KDE/Gnome. Go to the
Preferences menu, Environment and in the Emulation tab.&lt;/p&gt;

&lt;p&gt;There is &lt;strong&gt;no Vim layer&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&#34;searching-keybindings-by-name&#34;&gt;Searching keybindings by name&lt;/h3&gt;

&lt;p&gt;It is possible to search for a keybinding associated to a function, or
a function name from its keybinding, with the menu (Help -&amp;gt; Editing -&amp;gt;
Key to Command / Command to Key) or with &lt;code&gt;C-h&lt;/code&gt; followed by a key,
as in Emacs. For example type &lt;code&gt;C-h k&lt;/code&gt; then enter a keybinding to
get the command name. See more with &lt;code&gt;C-h ?&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;tweaking-the-ide&#34;&gt;Tweaking the IDE&lt;/h3&gt;

&lt;p&gt;It is possible to change keybindings. The editor&amp;rsquo;s state is accessible
from the &lt;code&gt;editor&lt;/code&gt; package, and the editor is built with the CAPI
framework, so we can use the &lt;code&gt;capi&lt;/code&gt; interface too. Useful functions
include:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;`
editor:bind-key
editor:defcommand
editor:current-point
editor:with-point  ;; save point location
editor:move-point
editor:*buffer-list*
editor:*in-listener* ;; returns T when we are in the REPL
…
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;rsquo;s how you can bind keys:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Indent new lines.
;; By default, the point is not indented after a Return.
(editor:bind-key &amp;quot;Indent New Line&amp;quot; #\Return :mode &amp;quot;Lisp&amp;quot;)

;; Insert pairs.
(editor:bind-key &amp;quot;Insert Parentheses For Selection&amp;quot; #\( :mode &amp;quot;Lisp&amp;quot;) ;;
(editor:bind-key &amp;quot;Insert Double Quotes For Selection&amp;quot; #\&amp;quot; :mode &amp;quot;Lisp&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;rsquo;s how to define a new command. We make the &lt;code&gt;)&lt;/code&gt; key
to go past the next closing parenthesis.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(editor:defcommand &amp;quot;Move Over ()&amp;quot; (p)
  &amp;quot;Move past the next close parenthesis.
Any indentation preceeding the parenthesis is deleted.&amp;quot;
  &amp;quot;Move past the next close parenthesis.&amp;quot;
  ;; thanks to Thomas Hermann
  ;; https://github.com/ThomasHermann/LispWorks/blob/master/editor.lisp
  (declare (ignore p))
  (let ((point (editor:current-point)))
    (editor:with-point ((m point))
      (cond ((editor::forward-up-list m)
	     (editor:move-point point m)
             (editor::point-before point)
             (loop (editor:with-point ((back point))
                     (editor::back-to-indentation back)
                     (unless (editor:point= back point)
                       (return)))
                   (editor::delete-indentation point))
	     (editor::point-after point))
	    (t (editor:editor-error))))))

(editor:bind-key &amp;quot;Move Over ()&amp;quot; #\) :mode &amp;quot;Lisp&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here&amp;rsquo;s how you can change indentation for special forms:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(editor:setup-indent &amp;quot;if&amp;quot; 1 4 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a list of LispWork keybindings: &lt;a href=&#34;https://www.nicklevine.org/declarative/lectures/additional/key-binds.html&#34;&gt;https://www.nicklevine.org/declarative/lectures/additional/key-binds.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;the-listener&#34;&gt;The listener&lt;/h3&gt;

&lt;p&gt;The listener is the REPL.&lt;/p&gt;

&lt;p&gt;Its interactive debugger is primarily textual but you can also
interact with it with graphical elements. For example, you can use the
Abort button of the menu bar, which brings you back to the top
level. You can invoke the graphical debugger to see the stacktraces
and interact with them. See the Debugger button at the very end of the
toolbar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/lispworks/toolbar-debugger.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;If you see the name of your function in the stacktraces (you will if
you wrote and compiled your code in a file, and not directly wrote it
in the REPL), you can double-click on its name to go back to the
editor and have it highlight the part of your code that triggered the
error.&lt;/p&gt;

&lt;div class=&#34;info-box info&#34;&gt;
&lt;!-- if inside a &lt;p&gt; then bootstrap adds 10px padding to the bottom --&gt;
&lt;strong&gt;NB:&lt;/strong&gt; this is equivalent of pressing &lt;code&gt;M-v&lt;/code&gt; in Slime.
&lt;/div&gt;

&lt;h3 id=&#34;the-stepper-breakpoints&#34;&gt;The stepper. Breakpoints.&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&#34;http://www.lispworks.com/documentation/lw61/IDE-W/html/ide-w-496.htm&#34;&gt;stepper&lt;/a&gt; is one
of the areas where LispWorks shines.&lt;/p&gt;

&lt;p&gt;When your are writing code in the editor window, you can set
breakpoints with the big red &amp;ldquo;Breakpoint&amp;rdquo; button (or by calling &lt;code&gt;M-x Stepper Breakpoint&lt;/code&gt;).
This puts a red mark in your code.&lt;/p&gt;

&lt;p&gt;The next time your code is executed, you&amp;rsquo;ll get a comprehensive Stepper pop-up window showing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your source code, with an indicator showing what expression is being evaluated&lt;/li&gt;
&lt;li&gt;a lower pane with two tabs:

&lt;ul&gt;
&lt;li&gt;the backtrace, showing the intermediate variables, thus showing their evolution during the execution of the program&lt;/li&gt;
&lt;li&gt;the listener, in the context of this function call, where you can evaluate expressions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;and the menu bar with the stepper controls: you can step into the next expression, step on the next function call, continue execution until the position of the cursor, continue the execution until the next breakpoint, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;/images/lispworks/stepper.gif&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s not all. The non-visual, REPL-oriented stepper is also nice. It shows the forms that are being evaluated and their results.&lt;/p&gt;

&lt;p&gt;In this example, we use &lt;code&gt;:s&lt;/code&gt; to &amp;ldquo;step&amp;rdquo; though the current form and its subforms. We are using the usual listener, we can write any Lisp code after the prompt (the little &lt;code&gt;-&amp;gt;&lt;/code&gt; here), and we have access to the local variables (&lt;code&gt;X&lt;/code&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER 4 &amp;gt; (defun my-abs (x) (cond ((&amp;gt; x 0) x) ((&amp;lt; x 0) (- x)) (t 0)))
CL-USER 5 &amp;gt; (step (my-abs -5))
(MY-ABS -5) -&amp;gt; :s
   -5 -&amp;gt; :s
   -5
   (COND ((&amp;gt; X 0) X) ((&amp;lt; X 0) (- X)) (T 0)) &amp;lt;=&amp;gt; (IF (&amp;gt; X 0) (PROGN X) (IF (&amp;lt; X 0) (- X) (PROGN 0)))
   ;; Access to the local variables:
   (IF (&amp;gt; X 0) (PROGN X) (IF (&amp;lt; X 0) (- X) (PROGN 0))) -&amp;gt; (format t &amp;quot;Is X equal to -5? ~a~&amp;amp;&amp;quot; (if (equal x -5) &amp;quot;yes&amp;quot; &amp;quot;no&amp;quot;))
Is X equal to -5? yes
   (IF (&amp;gt; X 0) (PROGN X) (IF (&amp;lt; X 0) (- X) (PROGN 0))) -&amp;gt; :s
      (&amp;gt; X 0) -&amp;gt; :s
         X -&amp;gt; :s
         -5
         0 -&amp;gt; :s
         0
      NIL
      (IF (&amp;lt; X 0) (- X) (PROGN 0)) -&amp;gt; :s
         (&amp;lt; X 0) -&amp;gt; :s
            X -&amp;gt; :s
            -5
            0 -&amp;gt; :s
            0
         T
         (- X) -&amp;gt; :s
            X -&amp;gt; :s
            -5
         5
      5
   5
5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here are the available stepper commands (see &lt;code&gt;:?&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:s       Step this form and all of its subforms (optional +ve integer arg)
:st      Step this form without stepping its subforms
:si      Step this form without stepping its arguments if it is a function call
:su      Step up out of this form without stepping its subforms
:sr      Return a value to use for this form
:sq      Quit from the current stepper level
:bug-form &amp;lt;subject&amp;gt; &amp;amp;key &amp;lt;filename&amp;gt;
         Print out a bug report form, optionally to a file.
:get &amp;lt;variable&amp;gt; &amp;lt;command identifier&amp;gt;
         Get a previous command (found by its number or a symbol/subform within it) and put it in a variable.
:help    Produce this list.
:his &amp;amp;optional &amp;lt;n1&amp;gt; &amp;lt;n2&amp;gt;
         List the command history, optionally the last n1 or range n1 to n2.
:redo &amp;amp;optional &amp;lt;command identifier&amp;gt;
         Redo a previous command, found by its number or a symbol/subform within it.
:use &amp;lt;new&amp;gt; &amp;lt;old&amp;gt; &amp;amp;optional &amp;lt;command identifier&amp;gt;
         Do variant of a previous command, replacing old symbol/subform with new symbol/subform.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;the-class-browser&#34;&gt;The class browser&lt;/h3&gt;

&lt;p&gt;The class browser allows us to examine a class&amp;rsquo;s slots, parent classes, available methods, and some more.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create a simple class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name :accessor name
         :initarg :name
         :initform &amp;quot;&amp;quot;)
   (lisper :accessor lisperp
           :initform t)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now call the class browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the &amp;ldquo;Class&amp;rdquo; button from the listener,&lt;/li&gt;
&lt;li&gt;or use the menu Expression -&amp;gt; Class,&lt;/li&gt;
&lt;li&gt;or put the cursor on the class and call &lt;code&gt;M-x Describe class&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;/images/lispworks/class-browser.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;It is composed of several panes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;class hierarchy&lt;/strong&gt;, showing the superclasses on the left and the subclasses on the right, with their description to the bottom,&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;superclasses viewer&lt;/strong&gt;, in the form of a simple schema, and the same for subclasses,&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;slots pane&lt;/strong&gt; (the default),&lt;/li&gt;
&lt;li&gt;the available &lt;strong&gt;initargs&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;the existing &lt;strong&gt;generic functions&lt;/strong&gt; for that class&lt;/li&gt;
&lt;li&gt;and the &lt;strong&gt;class precedence list&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Functions pane lists all methods applicable to that class, so we can discover public methods provided by the CLOS object system: &lt;code&gt;initialize-instance&lt;/code&gt;, &lt;code&gt;print-object&lt;/code&gt;, &lt;code&gt;shared-initialize&lt;/code&gt;, etc. We can double-click on them to go to their source. We can choose not to include the inherited methods too (see the &amp;ldquo;include inherited&amp;rdquo; checkbox).&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll find buttons on the toolbar (for example, Inspect a generic
function) and more actions on the Methods menu, such as a way to see
the &lt;strong&gt;functions calls&lt;/strong&gt;, a menu to &lt;strong&gt;undefine&lt;/strong&gt; or &lt;strong&gt;trace&lt;/strong&gt; a function.&lt;/p&gt;

&lt;p&gt;See more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-55.htm#pgfId-871798&#34;&gt;Chapter 8 of the documentation: the Class Browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;the-function-call-browser&#34;&gt;The function call browser&lt;/h3&gt;

&lt;p&gt;The function call browser allows us to see a graph of the callers and
the callees of a function. It provides several ways to filter the
displayed information and to further inspect the call stack.&lt;/p&gt;

&lt;div class=&#34;info-box info&#34;&gt;
&lt;!-- if inside a &lt;p&gt; then bootstrap adds 10px padding to the bottom --&gt;
&lt;strong&gt;NB:&lt;/strong&gt; The Slime functions to find such cross-references are &lt;code&gt;slime-who-[calls, references, binds, sets, depends-on, specializes, macroexpands]&lt;/code&gt;.
&lt;/div&gt;

&lt;p&gt;After loading a couple packages, here&amp;rsquo;s a simple example showing who calls the &lt;code&gt;string-trim&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/lispworks/function-call-browser.png&#34; alt=&#34;The function call browser&#34; /&gt;&lt;/p&gt;

&lt;p&gt;It shows functions from all packages, but there is a select box to restrict it further, for example to the &amp;ldquo;current and used&amp;rdquo; or only to the current packages.&lt;/p&gt;

&lt;p&gt;Double click on a function shown in the graph to go to its source. Again, as in many LispWorks views, the Function menu allows to further manipulate selected functions: trace, undefine, listen (paste the object to the Listener)…&lt;/p&gt;

&lt;p&gt;The Text tab shows the same information, but textually, the callers and callees side by side.&lt;/p&gt;

&lt;p&gt;We can see cross references for compiled code, and we must ensure the feature is on. When we compile code, LispWorks shows a compilation output likes this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 1
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3
;;; Source level debugging is on
;;; Source file recording is  on
;;; Cross referencing is on
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We see that cross referencing is on. Otherwise, activate it with &lt;code&gt;(toggle-source-debugging t)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-114.htm#pgfId-852601&#34;&gt;Chapter 15: the function call browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;the-process-browser&#34;&gt;The Process Browser&lt;/h3&gt;

&lt;p&gt;The Process Browser shows us a list of all threads running. The input area allows to filter by name. It accepts regular expressions. Then we can stop, inspect, listen, break into these processes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/images/lispworks/process-browser.png&#34; alt=&#34;&amp;quot;The process browser&amp;quot;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;See more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-178.htm#pgfId-852666&#34;&gt;Chapter 28: the Process Browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;using-lispworks-from-emacs-and-slime&#34;&gt;Using LispWorks from Emacs and Slime&lt;/h2&gt;

&lt;p&gt;To do that, start LispWorks normally, start a Swank server and connect to it from Emacs (Swank is the backend part of Slime).&lt;/p&gt;

&lt;p&gt;First, let&amp;rsquo;s load the dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;swank&amp;quot;)
;; or
(load &amp;quot;~/.emacs.d/elpa/slime-20xx/swank-loader.lisp&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start a server:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(swank:create-server :port 9876)
;; Swank started at port: 9876.
9876
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From Emacs, run &lt;code&gt;M-x slime-connect&lt;/code&gt;, choose &lt;code&gt;localhost&lt;/code&gt; and &lt;code&gt;9876&lt;/code&gt; for the port.&lt;/p&gt;

&lt;p&gt;You should be connected. Check with: &lt;code&gt;(lisp-implementation-type)&lt;/code&gt;. You are now able to use LispWorks&amp;rsquo; features:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setq button
      (make-instance &#39;capi:push-button
                     :data &amp;quot;Button&amp;quot;))
(capi:contain button)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u.htm&#34;&gt;LispWorks IDE User Guide&lt;/a&gt; (check out the sections we didn&amp;rsquo;t cover)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/LispWorks&#34;&gt;LispWorks on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/fourier/awesome-lispworks&#34;&gt;Awesome LispWorks&lt;/a&gt; list&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;And voilà, our review ends here. I&amp;rsquo;m happy to have this tool under my toolbet, and I want to explore the CAPI toolkit more. But for now I don&amp;rsquo;t use LispWorks daily, so if you do, don&amp;rsquo;t hesitate to leave a comment with a tip or to highlight a feature you really like. Thanks!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lem can now be started as a full featured Lisp REPL</title>
      <link>/blog/lem-can-be-started-as-a-full-featured-repl/</link>
      <pubDate>Wed, 24 Mar 2021 12:43:13 +0100</pubDate>
      
      <guid>/blog/lem-can-be-started-as-a-full-featured-repl/</guid>
      <description>

&lt;p&gt;The &lt;a href=&#34;https://github.com/lem-project/lem/&#34;&gt;Lem editor&lt;/a&gt;, which supports
Common Lisp as well as other languages, works by default in the
terminal with a ncurses frontend (it also has an experimental Electron
frontend). It ships a nice Lisp REPL: it has good fuzzy completion,
enough keyboard shortcuts, an interactive debugger, a completion menu,
etc.&lt;/p&gt;

&lt;p&gt;It is now possible to run Lem straight in its Lisp REPL. Run it with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;lem --eval &amp;quot;(lem-lisp-mode:start-lisp-repl t)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The optional argument (&lt;code&gt;t&lt;/code&gt;) was added recently (thanks, @cxxxr) and allows to start the REPL in fullscreen.&lt;/p&gt;

&lt;p&gt;Here is it in action:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/lem1.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/lem2.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/lem3.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/lem4.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The other terminal-based REPL alternatives are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/koji-kojiro/cl-repl/&#34;&gt;cl-repl&lt;/a&gt; (wants to be full-featured, à la ipython)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hellerve/sbcli&#34;&gt;sbcli&lt;/a&gt; (handy, but minimalistic)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;but IMO, they now fall short compared to Lem&amp;rsquo;s features.&lt;/p&gt;

&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;

&lt;p&gt;To install it, see its &lt;a href=&#34;https://github.com/lem-project/lem/wiki&#34;&gt;wiki&lt;/a&gt;. In short, do&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; ros install cxxxr/lem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or use &lt;a href=&#34;https://github.com/40ants/lem-docker&#34;&gt;lem-docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install Roswell, do one of&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew install roswell  # macos or linuxbrew
yay -S roswell
scoop install roswell  # windows

# Debian package:
curl -sOL `curl -s https://api.github.com/repos/roswell/roswell/releases/latest | jq -r &#39;.assets | .[] | select(.name|test(&amp;quot;deb$&amp;quot;)) | .browser_download_url&#39;`
sudo dpkg -i roswell.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See its &lt;a href=&#34;https://github.com/roswell/roswell/releases&#34;&gt;releases&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;usage-quickref&#34;&gt;Usage (quickref)&lt;/h2&gt;

&lt;p&gt;Lem has Emacs-like keybindings, as well as a vi emulation (&lt;code&gt;M-x vi-mode&lt;/code&gt;). Unfortunately, that is not documented much.&lt;/p&gt;

&lt;p&gt;So, to open a file, press &lt;code&gt;C-x C-f&lt;/code&gt; (you get the file selection dialog shown above). To save it, it&amp;rsquo;s &lt;code&gt;C-x C-s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To switch to the REPL: &lt;code&gt;C-c C-z&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To compile and load a buffer: &lt;code&gt;C-c C-k&lt;/code&gt;. To compile a function: &lt;code&gt;C-c C-c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To switch windows: &lt;code&gt;C-x o&lt;/code&gt;. To make a window fullscreen: &lt;code&gt;C-x 1&lt;/code&gt;. To split it vertically: &lt;code&gt;C-x 3&lt;/code&gt; and horizontally: &lt;code&gt;C-x 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To switch buffers: &lt;code&gt;C-x b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To run an interactive command: &lt;code&gt;M-x&lt;/code&gt; (&lt;code&gt;alt-x&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;See this Emacs &amp;amp; Slime cheatsheet to find more: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/emacs-ide.html#appendix&#34;&gt;https://lispcookbook.github.io/cl-cookbook/emacs-ide.html#appendix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lem works out of the box for several programming languages (Python, Rust, Scala…). It also has an HTML mode, a directory mode… Lem needs to be discovered!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chat: &lt;a href=&#34;https://gitter.im/lem-developers/community&#34;&gt;https://gitter.im/lem-developers/community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>State of the Common Lisp ecosystem, 2020  🎉</title>
      <link>/blog/state-of-the-common-lisp-ecosystem-2020/</link>
      <pubDate>Mon, 08 Feb 2021 11:29:11 +0200</pubDate>
      
      <guid>/blog/state-of-the-common-lisp-ecosystem-2020/</guid>
      <description>

&lt;p&gt;This is a description of the Common Lisp ecosystem, as of January, 2021,
from the perspective of a user and contributor.&lt;/p&gt;

&lt;p&gt;The purpose of this article is both to give an overview of the
ecosystem, and to help drive consolidation in each domain.&lt;/p&gt;

&lt;p&gt;Each application domain has recommendations for consolidating that
part of the ecosystem, and pointers for interesting future work.&lt;/p&gt;

&lt;p&gt;This article is derived from
Fernando Borretti&amp;rsquo;s &lt;a href=&#34;https://borretti.me/article/common-lisp-sotu-2015&#34;&gt;State of the Common Lisp ecosystem from 2015&lt;/a&gt;, hence the introduction that sounded familiar.
This new one will be an opportunity to look at what was achieved, or what is
still lacking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: This article is not a list of every project or article of interest that came out in the last years. I wrote an overview of 2018 closer to that goal &lt;a href=&#34;/blog/these-years-in-common-lisp-2018/&#34;&gt;here&lt;/a&gt;. More libraries can be discovered on the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome-cl&lt;/a&gt; list, on GitHub and on &lt;a href=&#34;https://www.cliki.net/&#34;&gt;Cliki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acknowledgements&lt;/strong&gt; I would like to thank @borodust, @ambrevar and @digikar for their kind feedback.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#application-domains&#34;&gt;Application domains&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#command-line&#34;&gt;Command line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#databases&#34;&gt;Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#concurrency&#34;&gt;Concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#file-formats&#34;&gt;File formats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gui&#34;&gt;GUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#machine-learning&#34;&gt;Machine Learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#system&#34;&gt;System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#web-development&#34;&gt;Web Development&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#backend&#34;&gt;Backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#frontend&#34;&gt;Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#javascript&#34;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#isomorphic-web-frameworks&#34;&gt;Isomorphic web frameworks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#languages-interop&#34;&gt;Languages interop&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#apl&#34;&gt;APL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#c-c-objective-c&#34;&gt;C, C++, Objective C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#clojure&#34;&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python&#34;&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#net-core&#34;&gt;.Net Core&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#development&#34;&gt;Development&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#implementations&#34;&gt;Implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#editors&#34;&gt;Editors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#developer-utilities&#34;&gt;Developer utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#package-management&#34;&gt;Package Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#build-system&#34;&gt;Build System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#type-system&#34;&gt;Type system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#testing-ci&#34;&gt;Testing, CI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#community&#34;&gt;Community&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#online-presence&#34;&gt;Online presence&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#new-common-lispnet-website&#34;&gt;New common-lisp.net website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cookbook&#34;&gt;Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#awesome-cl&#34;&gt;awesome-cl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#more&#34;&gt;More&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#new-books&#34;&gt;New books&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#companies&#34;&gt;Companies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#growth&#34;&gt;Growth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#last-words&#34;&gt;Last words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;application-domains&#34;&gt;Application domains&lt;/h1&gt;

&lt;h2 id=&#34;command-line&#34;&gt;Command line&lt;/h2&gt;

&lt;p&gt;There used to be several options to ease building and distribution of command line programs,
but now &lt;a href=&#34;https://github.com/snmsts/roswell&#34;&gt;Roswell&lt;/a&gt; has gained most momentum,
and that&amp;rsquo;s a good thing. Roswell is an implementation
manager, installer and a script runner, and one of its neat features is support for
very easily compiling tiny scripts into executables.&lt;/p&gt;

&lt;p&gt;Now, &lt;a href=&#34;https://guix.gnu.org/&#34;&gt;GNU Guix&lt;/a&gt; has gained many CL libraries, and becomes a contender to Roswell. Guix can be used as a package manager on top of your Unix distribution. It brings reproducible builds, rollbacks, the ability to install exact versions of any library (including system dependencies), contained environments and user profiles. It makes it easy too to install the latest version of a CL implementation and libraries and, to a certain extent, to share scripts. See the article &lt;a href=&#34;https://ambrevar.xyz/lisp-repl-shell/index.html&#34;&gt;A Lisp REPL as my main shell&lt;/a&gt; for insights.&lt;/p&gt;

&lt;p&gt;To parse command line arguments, &lt;a href=&#34;https://github.com/mrkkrp/unix-opts&#34;&gt;unix-opts&lt;/a&gt; shows decent activity. As a reminder, the CLI arguments are stored portably in &lt;code&gt;uiop:command-line-arguments&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/cl-adams/adams&#34;&gt;Adams&lt;/a&gt; is a new UNIX system administration tool, not unlike Chef or Ansible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;More features to the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#scripting&#34;&gt;sripting libraries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/cxxxr/lem/&#34;&gt;Lem editor&lt;/a&gt; has built a great user interface and REPL on top of ncurses, with the cl-charms library. It would be great to re-use its components, so that Lispers could easily build similar rich terminal-based interfaces.&lt;/p&gt;

&lt;h2 id=&#34;databases&#34;&gt;Databases&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/mito&#34;&gt;Mito&lt;/a&gt; is an ORM for Common Lisp
with migrations, relationships and PostgreSQL support. It is based on
cl-dbi (a uniform interface to the various database server-specific
libraries such as cl-postgres and cl-mysql) and SxQL (a DSL for
building safe, automatically parameterized SQL queries).&lt;/p&gt;

&lt;p&gt;It also has a tutorial in the Cookbook:
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;Cookbook/databases&lt;/a&gt;.&lt;/p&gt;

&lt;!-- On my blog, [an article](https://lisp-journey.gitlab.io/blog/composing-queries-with-mito-aka-replacing-lazy-querysets-and-q-objects/) --&gt;

&lt;!-- on how to compose queries with Mito and SxQL, and on how we only need --&gt;

&lt;!-- lisp knowledge to replace Django functionalities. --&gt;

&lt;p&gt;There are of course more libraries in that field. Some new ones since 2015 are:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/ruricolist/cl-yesql&#34;&gt;cl-yesql&lt;/a&gt; (by the author of
Serapeum, Spinneret and other great libraries) is based on Clojure&amp;rsquo;s
Yesql.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/kraison/vivace-graph-v3&#34;&gt;vivace-graph&lt;/a&gt; is a &lt;strong&gt;graph
database&lt;/strong&gt; and Prolog implementation, taking design and inspiration from
CouchDB, neo4j and AllegroGraph.&lt;/p&gt;

&lt;p&gt;Vsevolod Dyomkin, the author of Rutils, the Programming Algorithms
book and other libraries, is writing
&lt;a href=&#34;https://github.com/vseloved/cl-agraph&#34;&gt;cl-agraph&lt;/a&gt;, a minimal client
to Franz Inc&amp;rsquo;s &lt;a href=&#34;https://allegrograph.com/&#34;&gt;AllegroGraph&lt;/a&gt;. AllegroGraph is a
&amp;ldquo;horizontally distributed, multi-model (document and graph),
entity-event &lt;strong&gt;knowledge graph&lt;/strong&gt; technology&amp;rdquo;. It is proprietary and has a
free version with a limit of 5 million triples. Surely one of those Lisp hidden gems we should know more about.&lt;/p&gt;

&lt;p&gt;A general migration tool was lacking. We now have
&lt;a href=&#34;https://github.com/dnaeon/cl-migratum&#34;&gt;cl-migratum&lt;/a&gt;, a &amp;ldquo;system which
provides facilities for performing database schema migrations,
designed to work with various databases&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;And of course, &lt;a href=&#34;https://github.com/dimitri/pgloader&#34;&gt;pgloader&lt;/a&gt; is still a Common Lisp success story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Among the emerging ORMs, Mito is the one actively maintained that Lispers seem to have chosen. Good. CLSQL certainly still works, but we don&amp;rsquo;t hear about it and it looks outdated. So, Mito it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mito has 11 contributors and is actively watched, but it probably should have another(s) core maintainers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bindings for the new databases coming out.&lt;/p&gt;

&lt;h2 id=&#34;concurrency&#34;&gt;Concurrency&lt;/h2&gt;

&lt;p&gt;In the last year, Manfred Bergmann developed
&lt;a href=&#34;https://github.com/mdbergmann/cl-gserver&#34;&gt;cl-gserver&lt;/a&gt;. It is a
&amp;ldquo;message passing&amp;rdquo; library/framework with &lt;strong&gt;actors&lt;/strong&gt; similar to
&lt;strong&gt;Erlang&lt;/strong&gt; or &lt;strong&gt;Akka&lt;/strong&gt;. It is an important achievement.&lt;/p&gt;

&lt;p&gt;Its v1 features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;actors can use a shared pool of message dispatchers which effectively allows to create millions of actors.&lt;/li&gt;
&lt;li&gt;the possibility to create actor hierarchies. An actor can have child actors. An actor now can also &amp;ldquo;watch&amp;rdquo; another actor to get notified about its termination.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many other libraries exist in this area:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/bordeaux-threads/&#34;&gt;BordeauxThreads&lt;/a&gt; - Portable, shared-state concurrency

&lt;ul&gt;
&lt;li&gt;the &amp;ldquo;de-facto&amp;rdquo; concurrency library.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lmj/lparallel&#34;&gt;lparallel&lt;/a&gt; - A library for parallel programming.

&lt;ul&gt;
&lt;li&gt;also solid, battle-tested and popular, aka de-facto.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hawkir/calispel&#34;&gt;calispel&lt;/a&gt; - &lt;a href=&#34;https://en.wikipedia.org/wiki/Communicating_sequential_processes&#34;&gt;CSP&lt;/a&gt;-like channels for common lisp. With blocking, optionally buffered channels and a &amp;ldquo;CSP select&amp;rdquo; statement. ISC-style.

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;It is complete, flexible and easy to use. I would recommend Calispel over Lparallel and ChanL.&amp;rdquo; @Ambrevar. &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl/issues/290&#34;&gt;discussion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/zkat/chanl&#34;&gt;ChanL&lt;/a&gt; - Portable, channel-based concurrency.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/orthecreedence/cl-async&#34;&gt;cl-async&lt;/a&gt; - A library for general-purpose, non-blocking programming.

&lt;ul&gt;
&lt;li&gt;works atop libuv&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/TBRSS/moira&#34;&gt;Moira&lt;/a&gt; -  Monitor and restart background threads. In-lisp process supervisor.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/ediethelm/trivial-monitored-thread&#34;&gt;trivial-monitored-thread&lt;/a&gt; -
a Common Lisp library offering a way of spawning threads and being
informed when one any of them crash and die.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lmj/lfarm&#34;&gt;lfarm&lt;/a&gt; - distributing work across machines (on top of lparallel and usocket).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/taksatou/cl-gearman&#34;&gt;cl-gearman&lt;/a&gt; - a library for the &lt;a href=&#34;http://gearman.org/&#34;&gt;Gearman&lt;/a&gt; distributed job system.

&lt;ul&gt;
&lt;li&gt;Alexander Artemenko used it instead of lfarm for Ultralisp:
&lt;a href=&#34;https://40ants.com/lisp-project-of-the-day/2020/06/0095-cl-gearman.html&#34;&gt;https://40ants.com/lisp-project-of-the-day/2020/06/0095-cl-gearman.html&lt;/a&gt;,
because &amp;ldquo;lfarm is not well suited to environments where worker
hosts can go down and return back later&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/brown/swank-crew&#34;&gt;swank-crew&lt;/a&gt; - distributed computation framework implemented using Swank Client.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/takagi/cl-coroutine&#34;&gt;cl-coroutine&lt;/a&gt; - a coroutine library. It uses the CL-CONT continuations library in its implementation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cosmos72/stmx&#34;&gt;CMTX&lt;/a&gt;: high performance transactional memory for Common Lisp.

&lt;ul&gt;
&lt;li&gt;In our opinion, a library not well known and under-appreciated.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(see &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#parallelism-and-concurrency&#34;&gt;awesome-cl#parallelism-and-concurrency&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bordeaux-Threads is &lt;em&gt;the&lt;/em&gt; &amp;ldquo;de-facto&amp;rdquo; library, but there is some choice
paralysis between Lparallel, Calispel, Bordeaux-Threads and SBCL&amp;rsquo;s
contribs. Use the libraries in the wild and write about them.&lt;/p&gt;

&lt;h2 id=&#34;file-formats&#34;&gt;File formats&lt;/h2&gt;

&lt;p&gt;There exist Common Lisp libraries for all the major file formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XML: &lt;a href=&#34;https://github.com/Shinmera/plump&#34;&gt;Plump&lt;/a&gt; (and &lt;a href=&#34;https://github.com/Shinmera/lquery/&#34;&gt;Lquery&lt;/a&gt;), as well as &lt;a href=&#34;https://common-lisp.net/project/cxml/&#34;&gt;CXML&lt;/a&gt;, which can parse large files incrementally.&lt;/li&gt;
&lt;li&gt;JSON: &lt;a href=&#34;https://github.com/Rudolph-Miller/jonathan&#34;&gt;Jonathan&lt;/a&gt;, &lt;a href=&#34;https://common-lisp.net/project/cl-json/&#34;&gt;cl-json&lt;/a&gt; or &lt;a href=&#34;https://sabracrolleton.github.io/json-review&#34;&gt;more&lt;/a&gt;. With utilities:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/y2q-actionman/cl-json-pointer&#34;&gt;json-pointer&lt;/a&gt; - A JSON Pointer implementation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gschjetne/json-mop&#34;&gt;json-mop&lt;/a&gt; - A metaclass for bridging CLOS and JSON objects (remind that JSON libraries can already serialize your own objects).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fisxoj/json-schema&#34;&gt;json-schema&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;YAML: cl-yaml&lt;/li&gt;
&lt;li&gt;CSV: &lt;a href=&#34;https://github.com/AccelerationNet/cl-csv&#34;&gt;cl-csv&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;New in 2015, Jonathan is now a good first choice for an easy to use and fast JSON encoder and decoder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is not a predominant JSON library. This leads to choice paralysis.&lt;/p&gt;

&lt;p&gt;They all represent null values differently. We need a library that
&amp;ldquo;does the right thing&amp;rdquo;. See maybe the massive &lt;a href=&#34;https://github.com/xh4/web-toolkit#json&#34;&gt;web-toolkit&lt;/a&gt; for its JSON handling ?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It distinguishes null, false and [] from Lisp&amp;rsquo;s NIL thus supports identical transformation between JSON values. It provides object constructor and accessor to build and access nesting JSON objects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Give the &lt;a href=&#34;https://github.com/sharplispers/xpath&#34;&gt;XPath&lt;/a&gt; library some love and documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future Work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Still valid from 2015:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A YAML parser so that cl-yaml doesn’t depend on the libyaml library would make distribution far simpler.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;gui&#34;&gt;GUI&lt;/h2&gt;

&lt;p&gt;A usual complain in Common Lisp land is the lack of a complete,
cross-platform GUI solution. Ltk is a very good library, but Tk is
limited. Qtools is great, but is only for Qt4.&lt;/p&gt;

&lt;p&gt;A lot has happened, and is still happening (if you watch the right
repositories, you know that a Qt5 wrapper is in the works (ECL already has Qt5 bindings: &lt;a href=&#34;https://gitlab.com/eql/EQL5/&#34;&gt;EQL5&lt;/a&gt;, with an &lt;a href=&#34;https://gitlab.com/eql/EQL5-Android&#34;&gt;Android port&lt;/a&gt;)).&lt;/p&gt;

&lt;p&gt;edit: see also &lt;a href=&#34;https://gitlab.com/eql/eql5-sailfish&#34;&gt;EQL5-sailfish&lt;/a&gt; for Sailfish OS. &lt;a href=&#34;https://openrepos.net/user/13436/programs&#34;&gt;Here&lt;/a&gt; are two example apps.&lt;/p&gt;

&lt;p&gt;Matthew Kennedy wrote excellent FFI bindings to the IUP Portable User
Interface library: &lt;a href=&#34;https://github.com/lispnik/iup/&#34;&gt;IUP&lt;/a&gt;. IUP is
cross-platform (Windows, macOS, GNU/Linux, with new Android, iOS,
Cocoa and Web Assembly drivers), has many widgets (but less than Qt), has a small API and
is actively developed. IUP was created at the PUC university of Rio de Janeiro.&lt;/p&gt;

&lt;p&gt;Nicolas Hafner started &lt;a href=&#34;https://github.com/Shirakumo/alloy&#34;&gt;Alloy&lt;/a&gt;, a
new user interface protocol and toolkit implementation, which he uses in his Kandria game.&lt;/p&gt;

&lt;p&gt;Very recently, David Botton released &lt;a href=&#34;https://github.com/rabbibotton/clog&#34;&gt;CLOG&lt;/a&gt;, &amp;ldquo;the Common Lisp Omnificent GUI&amp;rdquo;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CLOG uses web technology to produce graphical user interfaces for applications locally or remotely. CLOG can take the place, or work alongside, most cross-platform GUI frameworks and website frameworks. The CLOG package starts up the connectivity to the browser or other websocket client (often a browser embedded in a native template application.)&lt;/p&gt;

&lt;p&gt;It is complete enough for most uses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are more GUI libraries and frameworks: &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#Gui&#34;&gt;https://github.com/CodyReichert/awesome-cl#Gui&lt;/a&gt; (and more under the works). In particular, LispWorks&amp;rsquo; CAPI is still presented as the best in town by the ones who tried it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since roughly October, 2020, Nicolas Hafner works full time on
&lt;a href=&#34;https://kandria.com/&#34;&gt;Kandria&lt;/a&gt;. Supporting his work, through &lt;a href=&#34;https://github.com/sponsors/Shinmera&#34;&gt;GitHub
sponsors&lt;/a&gt; or
&lt;a href=&#34;https://ko-fi.com/shinmera&#34;&gt;ko-fi&lt;/a&gt; would be 1) a great sign of recognition and 2) useful for the ecosystem, especially for Alloy.&lt;/p&gt;

&lt;p&gt;I wrote an introduction to these frameworks in the Cookbook:
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/gui.html&#34;&gt;Cookbook/gui&lt;/a&gt;. More
examples or demo projects would be welcome.&lt;/p&gt;

&lt;p&gt;There are two actively maintained diverged forks of the GTK bindings. A reunification effort is required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write a desktop application with IUP/your toolkit of choice for everyday use and make it a Common Lisp flagship.&lt;/p&gt;

&lt;p&gt;Study other approaches to GUI bindings. What about
&lt;a href=&#34;http://www.gtk-server.org/&#34;&gt;gtk-server&lt;/a&gt;? &lt;a href=&#34;https://github.com/andy128k/cl-gobject-introspection&#34;&gt;GObject introspection&lt;/a&gt;? An
effort started for Qt: &lt;a href=&#34;https://github.com/mrosset/giqt/&#34;&gt;giqt&lt;/a&gt; (in
which we recognize @ambrevar from the &lt;a href=&#34;https://github.com/atlas-engineer/nyxt/&#34;&gt;Nyxt
browser&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&#34;machine-learning&#34;&gt;Machine Learning&lt;/h2&gt;

&lt;p&gt;It seems that not much changed since 2015, but libraries are still being developed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmaul/clml&#34;&gt;CLML&lt;/a&gt;, developed at Mathematical Systems Inc., a Japanese company.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/melisgl/mgl&#34;&gt;MGL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;used by &lt;a href=&#34;http://quotenil.com/&#34;&gt;its author&lt;/a&gt; to win the &lt;a href=&#34;https://www.kaggle.com/c/higgs-boson&#34;&gt;Higgs Boson Machine Learning Challenge&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/melisgl/mgl-mat&#34;&gt;mgl-mat&lt;/a&gt; - a library for working with multi-dimensional arrays which supports efficient interfacing to foreign and CUDA code. BLAS and CUBLAS bindings are available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Others are less active:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.common-lisp.net/antik/antik&#34;&gt;Antik&lt;/a&gt; - a foundation for scientific and engineering computation in Common Lisp. It is designed not only to facilitate numerical computations, but to permit the use of numerical computation libraries and the interchange of data and procedures, whether foreign (non-Lisp) or Lisp libraries.

&lt;ul&gt;
&lt;li&gt;more than 2000 commits, last update 2 years ago.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;system&#34;&gt;System&lt;/h2&gt;

&lt;p&gt;To quote Fernando:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;UIOP, ASDF’s portable compatibility layer, contains a large set of tools for portably doing everything from querying the hostname to running external programs to manipulating environment variables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We should not require cl-fad anymore (but we need Osicat, which unlike UIOP is POSIX friendly).&lt;/p&gt;

&lt;p&gt;Built on top of UIOP, Paul M. Rodriguez&amp;rsquo;s &lt;a href=&#34;https://github.com/ruricolist/cmd&#34;&gt;cmd&lt;/a&gt; brings in short and handy helpers to run and pipe programs.&lt;/p&gt;

&lt;h2 id=&#34;web-development&#34;&gt;Web Development&lt;/h2&gt;

&lt;h3 id=&#34;backend&#34;&gt;Backend&lt;/h3&gt;

&lt;p&gt;Common Lisp&amp;rsquo;s main web servers are Hunchentoot and Clack. Since 2015, Clack&amp;rsquo;s documentation state barely improved and is still lacking.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/clack&#34;&gt;Clack&lt;/a&gt; is the equivalent of
WSGI/Rack. It has existed since 2009. It is an HTTP
server abstraction, that allows the user to write web applications
(or, more reasonably, web application frameworks) without depending on
a particular server. Some web frameworks are built on top of
it, for example &lt;a href=&#34;http://8arrow.org/caveman/&#34;&gt;Caveman2&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The importance of using Clack cannot be understated: If you build an application directly on, say, Hunchentoot, you’re tied to Hunchentoot, and if a new, faster server – like &lt;a href=&#34;https://github.com/fukamachi/woo&#34;&gt;Woo&lt;/a&gt; – comes out, you have to rewrite the entire application to use it. If you write a plugin for Clack – like &lt;a href=&#34;https://github.com/eudoxia0/clack-errors&#34;&gt;clack-errors&lt;/a&gt; – it is automatically usable by all applications, regardless of framework, that are built on Clack, reducing useless duplication of code.&lt;/p&gt;

&lt;p&gt;With Clack, switching from Hunchentoot to Woo, and enjoying the incredible speedup, is a simple matter of installing libev and changing a keyword argument.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This still holds true, but the situation didn&amp;rsquo;t improve much. In comparison, Hunchentoot is very well documented (and you can read its documentation on a better looking &lt;a href=&#34;https://common-lisp-libraries.readthedocs.io/hunchentoot/&#34;&gt;readthedocs here&lt;/a&gt;), and it is &amp;ldquo;fast enough&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;About Hunchentoot: Mariano Montone wrote &lt;a href=&#34;https://github.com/mmontone/easy-routes&#34;&gt;easy-routes&lt;/a&gt;, a little but handy route handling facility on top of Hunchentoot. It brings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dispatch by HTTP method,&lt;/li&gt;
&lt;li&gt;arguments extraction from the URL path,&lt;/li&gt;
&lt;li&gt;&amp;ldquo;decorators&amp;rdquo; to, for example, quickly add authorization checks,&lt;/li&gt;
&lt;li&gt;integration with the Djula framework to generate URLs from route names.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Several &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#clack-plugins&#34;&gt;Clack plugins&lt;/a&gt;
were written, such as a single-sign on middleware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write more documentation for Clack. While Lispers know about it,
they don&amp;rsquo;t necessarily adopt it because of the lack of
documentation. We can expand this &lt;a href=&#34;https://jasom.github.io/clack-tutorial/posts/getting-started-with-clack/&#34;&gt;getting started
guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a batteries-included framework.&lt;/p&gt;

&lt;h3 id=&#34;frontend&#34;&gt;Frontend&lt;/h3&gt;

&lt;p&gt;Many HTML generators and template libraries exist (see the list below). However, some new and good ones appeared lately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmontone/ten&#34;&gt;TEN&lt;/a&gt;, by Djula&amp;rsquo;s maintainer, brings the completness of Djula with the usability of Eco (by Fernando Borretti), aka: you write Django-like HTML templates but you can interleave any Lisp code.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/moderninterpreters/markup&#34;&gt;markup&lt;/a&gt; - a JSX-like templating engine, where HTML tags are Common Lisp code. Comes with an Emacs package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other HTML generators and templating engines include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ruricolist/spinneret&#34;&gt;spinneret&lt;/a&gt; - Common Lisp HTML5 generator.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://weitz.de/cl-who/&#34;&gt;cl-who&lt;/a&gt; - The venerable HTML generator.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmontone/djula&#34;&gt;Djula&lt;/a&gt; - A port of Django&amp;rsquo;s template engine to Common Lisp.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/archimag/cl-closure-template&#34;&gt;cl-closure-template&lt;/a&gt; - Implementation of Google&amp;rsquo;s Closure templates. [LLGPL][8].&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shinmera.github.io/clip&#34;&gt;clip&lt;/a&gt; - An HTML template processor where the templates are written in HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have nice other building blocks, such as a nice form handling
library (&lt;a href=&#34;https://github.com/mmontone/cl-forms&#34;&gt;cl-forms&lt;/a&gt;) and
libraries to create Open-API interfaces. An integrated, opinionated
all-in-one solution could be a productivity boom.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Djula is easy to work with. It could do with more built-in filters.&lt;/p&gt;

&lt;p&gt;As in 2015:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The foundation is finished, now it’s time to write higher-level layers. An extensible administration framework for Clack applications, like Django’s Admin, would be a good example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;javascript&#34;&gt;JavaScript&lt;/h3&gt;

&lt;p&gt;The two &amp;ldquo;historical&amp;rdquo; Common Lisp to JavaScript compilers are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vsedach/Parenscript&#34;&gt;Parenscript&lt;/a&gt;, a DSL that compiles a subset of Common Lisp to idiomatic JavaScript, and&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/davazp/jscl&#34;&gt;JSCL&lt;/a&gt;, a CL-to-JS compiler designed to be self-hosting from day one. JSCL is not complete (yet), it lacks CLOS, format and loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two new are in development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cxxxr/valtan&#34;&gt;Valtan&lt;/a&gt;, a CL to JS compiler.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tailrecursion.com/JACL/&#34;&gt;JACL&lt;/a&gt;, JavaScript Assisted Common LispIt has a &lt;a href=&#34;https://www.youtube.com/watch?v=JYLlC_dgQ5w&#34;&gt;recording from ELS 2020&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Help develop one of the existing CL-to-JS implementations. Why not have a look at
JSCL&amp;rsquo;s &lt;a href=&#34;https://github.com/jscl-project/jscl/issues&#34;&gt;issues&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Bring some new macros to ParenScript for new JavaScript idioms, as &lt;a href=&#34;https://github.com/BnMcGn/paren6/&#34;&gt;Paren6&lt;/a&gt;. For example, allow to write &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;isomorphic-web-frameworks&#34;&gt;Isomorphic web frameworks&lt;/h3&gt;

&lt;p&gt;Weblocks is an already old framework that allows to write dynamic web
applications without writing JavaScript (it isn&amp;rsquo;t as dynamic as modern
JS frameworks, there is no &amp;ldquo;double data binding&amp;rdquo;). Its server-based
components use Ajax if available or fallback to plain HTTP and
update the DOM. It is a framework in the vein of Smalltalk&amp;rsquo;s Seaside.&lt;/p&gt;

&lt;p&gt;Weblocks was getting old and unmaintained but Alexander Artemenko greatly updated and refactored it in his &lt;a href=&#34;https://github.com/40ants/weblocks/&#34;&gt;Reblocks&lt;/a&gt; branch. He uses it for the &lt;a href=&#34;https://ultralisp.org/&#34;&gt;Ultralisp&lt;/a&gt; website, and more apps. You can reach users and developers &lt;a href=&#34;https://gitter.im/40ants/weblocks&#34;&gt;on Gitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recently, a very new web framework appeared:
&lt;a href=&#34;https://github.com/interactive-ssr&#34;&gt;ISSR&lt;/a&gt;, for Interactive
Server-Side rendering. It links a client to the server with a
websocket connection and updates the DOM selectively. It is thus not
unlike Phoenix&amp;rsquo;s LiveView or
&lt;a href=&#34;https://github.com/hotwired/turbo&#34;&gt;Hotwire&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See this &lt;a href=&#34;http://cjackson.tk/todo-tutorial&#34;&gt;todo-app tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reviving Weblocks and releasing CLOG and ISSR are great achievements. However, work is only started to create a community of users around them.&lt;/p&gt;

&lt;h1 id=&#34;languages-interop&#34;&gt;Languages interop&lt;/h1&gt;

&lt;p&gt;New solutions arose to interoperate with other runtimes.&lt;/p&gt;

&lt;h2 id=&#34;apl&#34;&gt;APL&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/phantomics/april&#34;&gt;April&lt;/a&gt; brings the APL programming language (a subset thereof) to Common Lisp. Replace hundreds of lines of number-crunching code with a single line of APL.&lt;/p&gt;

&lt;h2 id=&#34;c-c-objective-c&#34;&gt;C, C++, Objective C&lt;/h2&gt;

&lt;p&gt;We had &lt;a href=&#34;https://github.com/cffi/cffi&#34;&gt;CFFI&lt;/a&gt; (a portable foreign function interface for CL), &lt;a href=&#34;https://github.com/rpav/c2ffi&#34;&gt;C2FFI&lt;/a&gt; (Clang-based FFI wrapper generator), then &lt;a href=&#34;https://github.com/rpav/cl-autowrap&#34;&gt;cl-autowrap&lt;/a&gt;, a c2ffi-based wrapper generator that makes creating C bindings real quick.&lt;/p&gt;

&lt;p&gt;Pavel Korolev is developing &lt;a href=&#34;https://github.com/borodust/claw&#34;&gt;CLAW&lt;/a&gt;, started as a fork of cl-autowrap, which brings &lt;strong&gt;C++ support&lt;/strong&gt;. For practice he generated bindings to GLM or &lt;a href=&#34;https://github.com/borodust/claw-filament&#34;&gt;to the Filament&lt;/a&gt; rendering engine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It will be a great achievement when CLAW is officially ready to use. This is not yet the case (though the GLM bindings basically do their hello world on Android, which is an achievement per se).&lt;/p&gt;

&lt;h2 id=&#34;clojure&#34;&gt;Clojure&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/lsevero/abclj&#34;&gt;ABCLJ&lt;/a&gt; provides a &amp;ldquo;dead easy  Clojure to Common lisp interop&amp;rdquo;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;instead of rewriting the whole Clojure langugage on CL I&amp;rsquo;m embedding ABCL in Clojure. Since both are implemented in Java and Clojure has an awesome java interop is easy to have full access on the ABCL Common Lisp environment. This way we have complete support for both Clojure and Common Lisp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But why?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The reason I wanted to see Clojure and Common Lisp working with each other was to use CL programs/libraries on Clojure, especially Maxima and ACL2. Since ABCL already compiles and runs Maxima it should be possible but we are very far from it 🤷.&lt;/p&gt;

&lt;p&gt;There are others of attempts to shorten the gap between clojure and common lisp like Cloture and clclojure. Once they are complete Clojure will benefit from native binaries and excelent compilers like SBCL, however they are far from complete.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the topic, see this talk by Alan Dipert: &lt;a href=&#34;https://www.youtube.com/watch?v=44Q9ew9JH_U&#34;&gt;&amp;ldquo;Common Lisp for the curious Clojurian&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Abstract:&lt;/p&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
&lt;p&gt;“If I had to be stranded with something other than Clojure, I’d be happiest with a good Common Lisp and its source code.” - Rich Hickey, 2011&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Common Lisp (CL) and Clojure are both dialects of Lisp. Rich Hickey, the creator of Clojure, learned CL and used it professionally before creating Clojure.&lt;/p&gt;

&lt;p&gt;What can Clojure do that CL can’t, and vice versa? Why would anyone use CL today, when both Clojure and ClojureScript exist?&lt;/p&gt;

&lt;p&gt;In this talk, I will try to answer these questions and more, from the perspective of a long-time Clojurian with a growing passion for CL.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;python&#34;&gt;Python&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/bendudson/py4cl&#34;&gt;py4cl&lt;/a&gt; is the new lib in town. It allows Common Lisp code to access Python libraries. It is basically the inverse of &lt;a href=&#34;https://github.com/marcoheisig/cl4py&#34;&gt;cl4py&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See also &lt;a href=&#34;https://github.com/cxxxr/async-process/&#34;&gt;async-process&lt;/a&gt; and,
while we&amp;rsquo;re at it, my &lt;a href=&#34;/pythonvslisp&#34;&gt;comparison of Python VS Common
Lisp&lt;/a&gt;, where we look at the differences of workflows and
ecosystems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calling to Python and hooking into its ecosystem is easier than ever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Improving CL libraries such as
&lt;a href=&#34;https://github.com/numcl/numcl&#34;&gt;Numcl&lt;/a&gt; (a Numpy clone) is what&amp;rsquo;s
required to drive Common Lisp forward.&lt;/p&gt;

&lt;h2 id=&#34;net-core&#34;&gt;.Net Core&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Lovesan/bike&#34;&gt;Bike&lt;/a&gt; is a cross-platform .Net Core interface.&lt;/p&gt;

&lt;h1 id=&#34;development&#34;&gt;Development&lt;/h1&gt;

&lt;h2 id=&#34;implementations&#34;&gt;Implementations&lt;/h2&gt;

&lt;p&gt;All implementations saw new releases, except CLisp, whose development however continues.&lt;/p&gt;

&lt;p&gt;Active implementations include: ABCL, CCL, CLASP, ECL, LispWorks, AllegroCL, SBCL. And to a certain extent, GNU CLisp, SICL (which is the newest one) and Corman Lisp (a CL development environment for Windows) (regenerated &lt;a href=&#34;https://github.com/sharplispers/cormanlisp&#34;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;ABCL &lt;a href=&#34;https://abcl-dev.blogspot.com/2020/10/abcl-180.html&#34;&gt;jumped to v1.8.0&lt;/a&gt; to support openjdk15.&lt;/p&gt;

&lt;p&gt;SBCL still ships monthly releases. It turned 20 and keeps improving (RISC-V port, M1 port, block compilation, more compile-time type checking…). We can read a blog on the party held in Vienna &lt;a href=&#34;https://mstmetent.blogspot.com/2020/01/sbcl20-in-vienna-last-month-i-attended.html&#34;&gt;here&lt;/a&gt;. Did you know that Doug Katzman of Google fame contributes to SBCL?&lt;/p&gt;

&lt;p&gt;(edit:)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Doug Katzman talked about his work at Google getting SBCL to work with Unix better. For those of you who don’t know, he’s done a lot of work on SBCL over the past couple of years, not only adding a lot of new features to the GC and making it play better with applications which have alien parts to them, but also has done a tremendous amount of cleanup on the internals and has helped SBCL become even more Sanely Bootstrappable. That’s a topic for another time, and I hope Doug or Christophe will have the time to write up about the recent improvements to the process, since it really is quite interesting.&lt;/p&gt;

&lt;p&gt;Anyway, what Doug talked about was his work on making SBCL more amenable to external debugging tools, such as gdb and external profilers. It seems like they interface with aliens a lot from Lisp at Google, so it’s nice to have backtraces from alien tools understand Lisp. It turns out a lot of prerequisite work was needed to make SBCL play nice like this, including implementing a non-moving GC runtime, so that Lisp objects and especially Lisp code (which are normally dynamic space objects and move around just like everything else) can’t evade the aliens and will always have known locations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!-- SICL was able to load the Alexandria library. Some of its components are already used in the wild (for example, the [Eclector](https://github.com/s-expressionists/Eclector) Common Lisp reader). --&gt;

&lt;h2 id=&#34;editors&#34;&gt;Editors&lt;/h2&gt;

&lt;p&gt;Here too, great progress has been made. While a usual complain of non-Lispers was the lack of editor support besides Emacs (and Vim), we now nearly reach choice paralysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://portacle.github.io/&#34;&gt;Portacle&lt;/a&gt; is the easiest way to get started with Emacs. It is portable and multi-platform, ready-to-use in three clicks. It ships Emacs, SBCL, Slime, Quicklisp and git.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/neil-lindquist/SLIMA/&#34;&gt;SLIMA&lt;/a&gt; is the Atom extension. It is nearly as good as Slime for Emacs.&lt;/li&gt;
&lt;li&gt;VSCode has two extensions: &lt;a href=&#34;https://github.com/ailisp/commonlisp-vscode&#34;&gt;commonlisp-vscode&lt;/a&gt;, using the Language Server Protocol, and &lt;a href=&#34;https://github.com/nobody-famous/alive&#34;&gt;Alive&lt;/a&gt;, more recent, using a Lisp backend (Swank) as traditional extensions.&lt;/li&gt;
&lt;li&gt;Sublime Text got a good extension: &lt;a href=&#34;https://github.com/s-clerc/slyblime&#34;&gt;Slyblime&lt;/a&gt; is an implementation of SLY and it uses the same backend (SLYNK). It ships advanced features including a debugger with stack frame inspection.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cxxxr/lem/&#34;&gt;Lem&lt;/a&gt; is an editor written in Common Lisp. It allows to start developing in CL at once, and it supports other languages.&lt;/li&gt;
&lt;li&gt;we have a &lt;a href=&#34;https://github.com/yitzchak/common-lisp-jupyter&#34;&gt;Jupyter kernel&lt;/a&gt; for CL.&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/Ragnaroek/dandelion/&#34;&gt;Dandelion Eclipse plugin&lt;/a&gt; was re-discovered. While it isn&amp;rsquo;t as feature-rich as others (no interactive debugger for example), it has its users. It specifically targets beginners.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last but not least, if you want to play in your iPhone or iPad, the &lt;a href=&#34;https://codeplayground.app/&#34;&gt;CodePlayground&lt;/a&gt; app got Lisp support via CCL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/joaotavora/sly&#34;&gt;SLY&lt;/a&gt; might need more praise. It has sound features such as SLY stickers and the new &lt;a href=&#34;https://github.com/joaotavora/sly-stepper&#34;&gt;SLY stepper&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;developer-utilities&#34;&gt;Developer utilities&lt;/h2&gt;

&lt;p&gt;Life continues to improve for the developper. We will cite some new tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/cl-flamegraph&#34;&gt;cl-flamegraph&lt;/a&gt; is a wrapper around SBCL&amp;rsquo;s statistical profiler to generate FlameGraph charts from Common Lisp programs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/TeMPOraL/tracer&#34;&gt;tracer&lt;/a&gt; is a tracing profiler for Common Lisp, with output suitable for display in Chrome’s/Chromium’s Tracing Viewer.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.martin-loetzsch.de/gtfl/&#34;&gt;GTFL&lt;/a&gt; is a graphical terminal for Lisp, meant for Lisp programmers who want to debug or visualize their own algorithms. It is a graphical trace in the browser.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/ambrevar/lisp-repl-core-dumper/&#34;&gt;Lisp REPL core dumper&lt;/a&gt; is a portable wrapper to generate Lisp cores on demand to start a REPL blazingly fast. It can preload provided systems to help build a collection of specialized Lisp cores.

&lt;ul&gt;
&lt;li&gt;if you are used to working in different environments that require their own set of libraries, this core dumper (optionally along with SLY&amp;rsquo;s mrepl) can make switching from one another easier and faster.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;package-management&#34;&gt;Package Management&lt;/h2&gt;

&lt;p&gt;Quicklisp is the de-facto package manager. However, we now have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ultralisp.org/&#34;&gt;Ultralisp&lt;/a&gt;, a Quicklisp distribution that builds every 5 minutes. We can add our project in two clicks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.common-lisp.net/clpm/clpm&#34;&gt;CLPM&lt;/a&gt;, a new package manager that is compatible with Quicklisp, that allows to pin exact versions of dependencies, that is usable from the command line and that supports HTTPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not forgetting Qlot, to install Quicklisp libraries relative to a directory.&lt;/p&gt;

&lt;p&gt;Last but not least, as said earlier, many CL libraries were packaged for Guix (most notably by &lt;a href=&#34;https://ambrevar.xyz&#34;&gt;Pierre Neidhart&lt;/a&gt; of Nyxt).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achievement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ultralisp solves the 1-month release schedule of Quicklisp (which is a feature, but not to everyone&amp;rsquo;s taste) and makes it straightforward and quick to publish a library. CLPM by tackling a different approach solves other Quicklisp limitations. Both are great achievements.&lt;/p&gt;

&lt;p&gt;Ultralisp also has a search box that searches a symbol on all its registered libraries. Very useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alexander is working on allowing every Ultralisp user to create his own Quicklisp dist in a few clicks.&lt;/p&gt;

&lt;h2 id=&#34;build-system&#34;&gt;Build System&lt;/h2&gt;

&lt;p&gt;Same as 2015, ASDF is the de-facto build system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every project has an .asd file, called a system definition file, which defines project metadata (author, maintainer, homepage, etc.) and the components.&lt;/p&gt;

&lt;p&gt;This, to me, is one of the major selling points of Common Lisp. With languages like Python, every file imports whatever it needs, and your project becomes a massive graph of interdependent files. In ASDF, you basically list the files in your project in the order in which they are defined. Or, you can specify the dependencies between the files, and let ASDF figure out a linear ordering. The point is that dependencies are explicit, and clearly spelled out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!-- ## Documentation --&gt;

&lt;h2 id=&#34;type-system&#34;&gt;Type system&lt;/h2&gt;

&lt;p&gt;Quoting Fernando:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There’s not much to say here, except that Common Lisp has a pretty great type system that is not exploited nearly enough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And to our greatest pleasure, SBCL&amp;rsquo;s type system continues to improve. For example, SBCL 1.5.9 now gives type warnings when a slot declared type doesn&amp;rsquo;t match its &lt;code&gt;initform&lt;/code&gt;. It continued to improve on SBCL 2.0 and onwards.&lt;/p&gt;

&lt;p&gt;Moreover, the &lt;a href=&#34;https://github.com/stylewarning/coalton/&#34;&gt;Coalton&lt;/a&gt; library is bringing a dialect of ML on top of CL, in order to write &lt;strong&gt;statically typed programs&lt;/strong&gt; similar in spirit to Standard ML, OCaml, and Haskell.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Help develop Coalton.&lt;/p&gt;

&lt;h2 id=&#34;testing-ci&#34;&gt;Testing, CI&lt;/h2&gt;

&lt;p&gt;Fernando cited &lt;a href=&#34;https://common-lisp.net/project/fiveam/docs/Introduction.html&#34;&gt;FiveAM&lt;/a&gt; and recommended it along with the much newer
Prove. Prove has a couple issues and is now deprecated by its author,
and its younger brother Rove is not in par yet.&lt;/p&gt;

&lt;p&gt;So, use FiveAM.&lt;/p&gt;

&lt;p&gt;Moreover, Common Lisp has good support for the CI/CD services out there.&lt;/p&gt;

&lt;p&gt;CL Foundation&amp;rsquo;s Docker images have integrated best practices over the
years and are recommended:
&lt;a href=&#34;https://common-lisp.net/project/cl-docker-images/&#34;&gt;https://common-lisp.net/project/cl-docker-images/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/neil-lindquist/CI-Utils&#34;&gt;CI-Utils&lt;/a&gt; regroups
utilities for various platforms (Travis, Circle, Gitlab, Github,
Appveyor, Bitbucket, Azure) and test frameworks.&lt;/p&gt;

&lt;p&gt;We got a comprehensive blog post for GitHub actions: &lt;a href=&#34;http://3bb.cc/blog/2020/09/11/github-ci/&#34;&gt;part1&lt;/a&gt; and &lt;a href=&#34;http://3bb.cc/blog/2020/09/13/github-ci2/&#34;&gt;part2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Travis CI, you can also see &lt;a href=&#34;https://github.com/luismbo/cl-travis&#34;&gt;cl-travis&lt;/a&gt; (for ABCL, Allegro CL, SBCL, CMUCL, CCL and ECL).&lt;/p&gt;

&lt;p&gt;You will find an example for Gitlab CI on the Cookbook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rove or &lt;a href=&#34;https://github.com/Shinmera/parachute&#34;&gt;Parachute&lt;/a&gt; would be great alternatives if developed a bit further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integration with the CI services&amp;rsquo; advanced features such as Gitlab&amp;rsquo;s auto DevOps.&lt;/p&gt;

&lt;!-- ## Libraries --&gt;

&lt;!-- Not sure about where to put this, but I wanted to cite [generic-cl](https://github.com/alex-gutev/generic-cl/), a &#34;generic function interface to standard Common Lisp functions&#34;. A common complain about Common Lisp is the number of equality predicates, and the fact that all core data structures are not based on the object system and, consequently, we can&#39;t define our own `=` operator for custom objects. This --&gt;

&lt;h1 id=&#34;community&#34;&gt;Community&lt;/h1&gt;

&lt;h2 id=&#34;online-presence&#34;&gt;Online presence&lt;/h2&gt;

&lt;p&gt;Common Lisp is very well documented through its standard, the Common
Lisp Hyper Spec and many books. However, we felt it was lacking good
on-line material. Good news is, the situation improved tremendously in
the last three or four years.&lt;/p&gt;

&lt;h3 id=&#34;new-common-lisp-net-website&#34;&gt;New common-lisp.net website&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://common-lisp.net&#34;&gt;https://common-lisp.net&lt;/a&gt; was written anew. It looked dated. This is now fixed. Well done!&lt;/p&gt;

&lt;h3 id=&#34;cookbook&#34;&gt;Cookbook&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;Common Lisp Cookbook&lt;/a&gt; on GitHub got revived by many new contributors, included myself. It got many new content and a new UI. It is also now available in ePub and PDF, for free or as a &amp;ldquo;pay what you want&amp;rdquo; option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write content on the Cookbook. Don&amp;rsquo;t write tutorials on your blog. Everyone can help, even new Lispers (and in fact: &lt;em&gt;mostly&lt;/em&gt; new Lispers can write content best suited to the Cookbook&amp;rsquo;s target audience).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make it look world-class with a real and modern theme.&lt;/p&gt;

&lt;p&gt;Help revive the &lt;a href=&#34;https://github.com/lamberta/minispec&#34;&gt;minispec&lt;/a&gt; ?&lt;/p&gt;

&lt;h3 id=&#34;awesome-cl&#34;&gt;awesome-cl&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;awesome-cl&lt;/a&gt; list saw continuous updates and is  now a great solution to have an overview of the ecosystem and choose a library.&lt;/p&gt;

&lt;p&gt;One of its goals is to break choice paralysis by recommending libraries, with its &amp;ldquo;+1&amp;rdquo; marks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Help furnish and curate it.&lt;/p&gt;

&lt;h3 id=&#34;more&#34;&gt;More&lt;/h3&gt;

&lt;p&gt;A first Common Lisp User survey was run, we can consult its results here &lt;a href=&#34;https://docs.google.com/forms/d/e/1FAIpQLSfg7UJRKrkI3OjOHWL4xI-murE4LpQjIxsiAhFdPEmtyLX3kg/viewanalytics&#34;&gt;on Google docs&lt;/a&gt; and read comments &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/jwdimb/state_of_common_lisp_survey_2020_raw_results/&#34;&gt;on reddit&lt;/a&gt; as well as feedback on the questions &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/f8wqkj/state_of_common_lisp_survey_2020/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I agree with /u/defunkydrummer here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that many, many things that people wish to see, are already available, so perhaps we, as a community, are not fully communicating the state of our ecosystem even to our insiders (!)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Several popular libraries have been ported to readthedocs, so the reading experience is more pleasant: &lt;a href=&#34;https://common-lisp-libraries.readthedocs.io/&#34;&gt;https://common-lisp-libraries.readthedocs.io/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Michal &amp;ldquo;phoe&amp;rdquo; Herda organized many online Lisp meetings, and we can find the videos on Youtube: &lt;a href=&#34;https://www.youtube.com/c/OnlineLispMeetings/videos&#34;&gt;https://www.youtube.com/c/OnlineLispMeetings/videos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alexander Artemenko started &lt;a href=&#34;https://40ants.com/lisp-project-of-the-day/&#34;&gt;lisp project of the day&lt;/a&gt;, a blog to review a library every day for a month, and he is now at post #219. Lately he reviewed many documentation builders for CL.&lt;/p&gt;

&lt;p&gt;On a sadder note, Quickdocs closed :(&lt;/p&gt;

&lt;h2 id=&#34;new-books&#34;&gt;New books&lt;/h2&gt;

&lt;p&gt;We got 3 new books on Common Lisp in 2020:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://vseloved.github.io/progalgs.html&#34;&gt;Programming Algorithms&lt;/a&gt;, originally published by Vsevolod Dyomkin on his website, then self-published in paperback and then published by Apress.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Apress/common-lisp-condition-system/&#34;&gt;the Common Lisp Condition System&lt;/a&gt;, by Michal &amp;ldquo;phoe&amp;rdquo; Herda, was also published by himself and then by Apress.&lt;/li&gt;
&lt;li&gt;The Cookbook that was made available in ePub and PDF :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the book &lt;a href=&#34;https://www.cambridge.org/us/academic/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition?format=HB#resources&#34;&gt;Calendrical calculations&lt;/a&gt;, 4th edition, by Edward M. Reingold, Nachum Dershowitz, Cambridge Press. It provides Lisp sources.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.qrg.northwestern.edu/bps/readme.html&#34;&gt;Building Problem Solvers&lt;/a&gt;, by Kenneth Forbus and Johan de Kleer, MIT Press, was made available.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;companies&#34;&gt;Companies&lt;/h2&gt;

&lt;p&gt;We now have a curated list of companies using CL: &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies&#34;&gt;awesome-cl-companies&lt;/a&gt;. Before that list, the situation was embarassing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everyone says “Nobody uses Lisp” and Lispers say “Yes they do, there’s ITA, and, um, Autocad, and, uh, oh yeah, Paul Graham wrote Viaweb in Lisp!” Not very helpful for either side. It’s about time there was a better resource.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;http://pchristensen.com/blog/lisp-companies/&#34;&gt;Peter Christensen in his first list&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And see also &lt;a href=&#34;https://lisp-lang.org/success/&#34;&gt;lisp-lang.org&amp;rsquo;s success stories&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some additions of this year include
&lt;a href=&#34;https://graphmetrix.com/&#34;&gt;GraphMetrix&lt;/a&gt; (automation of document extraction and publishing for construction, property and logistics),
Doremir Music Research AB (developing &lt;a href=&#34;https://scorecloud.com/&#34;&gt;ScoreCloud&lt;/a&gt;, a music notation software: you sing, it writes the score),
&lt;a href=&#34;https://www.keepit.com/&#34;&gt;Keepit&lt;/a&gt; (a cloud-to-cloud backup service provider),
&lt;a href=&#34;https://www.mind.ai&#34;&gt;Mind AI&lt;/a&gt; (an artificial intelligence engine and ecosystem),
&lt;a href=&#34;http://insurevip.co.uk&#34;&gt;Virtual Insurance Products Ltd&lt;/a&gt; (insurance MGA with a bespoke business to business web platform) or again
&lt;a href=&#34;https://mimix.io/&#34;&gt;the Mimix Company&lt;/a&gt; (creators of MSL and Nebula, new tools for working with facts and documents).&lt;/p&gt;

&lt;h2 id=&#34;growth&#34;&gt;Growth&lt;/h2&gt;

&lt;p&gt;We are able to compare the number of downloads of the 100 most popular Quicklisp libraries between 2015 and 2020:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/sotu-downloads-2020.png&#34; alt=&#34;&#34; title=&#34;Comparing total downloads of Quicklisp libraries shows a 3x increase between 2015 and 2020.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;We can observe a 3x growth in five years. Of course, these figures need to be taken with a grain of salt, what they really represent is subject to interpretation. What is the role of Continuous Integration here?&lt;/p&gt;

&lt;p&gt;Check it yourself: &lt;a href=&#34;https://gitlab.com/-/snippets/2070318&#34;&gt;snippet&lt;/a&gt;, &lt;a href=&#34;https://jsfiddle.net/1q3xjyeL/1/&#34;&gt;JSFiddle&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;last-words&#34;&gt;Last words&lt;/h1&gt;

&lt;p&gt;Many things are happening in the CL universe. Stay tuned!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;The &lt;a href=&#34;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/-/blob/master/content/blog/state-of-the-common-lisp-ecosystem-2020.md#implementations&#34;&gt;article source&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Common Lisp Cookbook Is Now Available in EPUB and PDF</title>
      <link>/blog/the-common-lisp-cookbook-is-now-available-in-epub-and-pdf/</link>
      <pubDate>Tue, 19 Jan 2021 11:32:25 +0100</pubDate>
      
      <guid>/blog/the-common-lisp-cookbook-is-now-available-in-epub-and-pdf/</guid>
      <description>&lt;p&gt;I am glad to announce that the Common Lisp Cookbook is now available in ePub and PDF.&lt;/p&gt;

&lt;p&gt;It is available for free, and you can pay what you want[1] to say a
loud &amp;ldquo;thank you&amp;rdquo; and to further support its development. Thanks!&lt;/p&gt;

&lt;p&gt;This EPUB represents the work on the span of three years where I have been constantly reading, experimenting, asking, discovering tips, tools, libraries and best-practices, built-in or not, all of which should have been easily accessible but were not. Now they are. Reviving the Cookbook project resonated in the community, as other lispers sent great contributions.&lt;/p&gt;

&lt;p&gt;&lt;a style=&#34;font-size: 16px; background-color: #4CAF50; color: white; padding: 16px; cursor: pointer;&#34; href=&#34;https://ko-fi.com/s/01fee22a32&#34;&gt;
  Donate and download the EPUB version
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;=&amp;gt; &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/&#34;&gt;https://lispcookbook.github.io/cl-cookbook/&lt;/a&gt; &amp;lt;=&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;[1]: above 6 USD actually.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Another Common Lisp app in production</title>
      <link>/blog/another-common-lisp-app-in-production/</link>
      <pubDate>Mon, 14 Dec 2020 22:54:28 +0100</pubDate>
      
      <guid>/blog/another-common-lisp-app-in-production/</guid>
      <description>&lt;p&gt;A quick post to celebrate the birth of another Common Lisp application
running in production©. This time, it is not open source, but I can describe it.&lt;/p&gt;

&lt;p&gt;It is used by bookshops in France and Belgium to upload their catalogue to online
platforms. And no, they don&amp;rsquo;t know, and don&amp;rsquo;t need to know, the
language it is implemented in!&lt;/p&gt;

&lt;p&gt;It is a simple application that reads data from an existing DB, builds
a text file with special rules, sends the file to an FTP server, and
does it every day. I used cl-dbi with raw SQL queries,
&lt;a href=&#34;https://github.com/pinterface/cl-ftp&#34;&gt;cl-ftp&lt;/a&gt; (does its job perfectly), and a CRON job. I
built a binary that I sent to my server. It is a stand-alone
application that reads a DB that is created by a bigger Python/Django
web app (that I also develop). I didn&amp;rsquo;t want to make this one more
bloated, so given the goals are complementary but orthogonal, I went
with a stand-alone tool.&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s it. One more!&lt;/p&gt;

&lt;p&gt;Another tool I am running connects to a SOAP service, shows data on a website (with Sentry configured in production), sells products with Stripe (edit: it&amp;rsquo;s postponed :/ ) and sends emails with Sendgrid. And I (generally) update it while it runs by connecting to the Lisp REPL. Just throwing out buzzwords to you.&lt;/p&gt;

&lt;p&gt;While I&amp;rsquo;m at it, let me stress one point, to answer in advance a kind
of feedback I already had: no, the resulting application doesn&amp;rsquo;t use
any Lisp superpower and yes, I could have written it in Python. It
turns out Lisp is as suited as Python for this task (or then it is
more suited, since it is faster), the point is &lt;em&gt;I&lt;/em&gt; benefited from Lisp&amp;rsquo;s
superpowers during development (by using the superior REPL, being able
to build a binary and all that). In conclusion: there are &lt;strong&gt;tons&lt;/strong&gt; of
places where Lisp can be used for professional needs out there.&lt;/p&gt;

&lt;p&gt;Oh. In doing it, I built those &lt;del&gt;two&lt;/del&gt; three utilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-sendgrid&#34;&gt;cl-sendgrid&lt;/a&gt;, a trivial interface to the Sendgrid API (to send emails).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/progressons&#34;&gt;progressons&lt;/a&gt;, a progress bar that holds on one line and works on the terminal as well as on Slime. It works for me©. My next goal is to make it output a prettier bar with unicode bars.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/termp&#34;&gt;termp&lt;/a&gt;, a trivial utility that checks if we are on a real or on a dumb terminal (by checking the &lt;code&gt;TERM&lt;/code&gt; environment variable). So you can &lt;code&gt;quit&lt;/code&gt; or &lt;code&gt;error&lt;/code&gt; out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More Lisp repositories on Github !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pro mailing list: on Common Lisp and parallel GC</title>
      <link>/blog/pro-mailing-list-on-common-lisp-and-parallel-gc/</link>
      <pubDate>Mon, 14 Dec 2020 22:41:32 +0100</pubDate>
      
      <guid>/blog/pro-mailing-list-on-common-lisp-and-parallel-gc/</guid>
      <description>&lt;p&gt;I recently enjoyed this &lt;a href=&#34;https://mailman.common-lisp.net/pipermail/pro/2020-December/thread.html#1837&#34;&gt;discussion on the pro mailing list&lt;/a&gt;. It started with a call of recommendations on music software, and the discussion evolved in discussing parallel garbage collection. By the way, can you site an implementation that has parallel GC?&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Pascal Costanza:&lt;/p&gt;

&lt;p&gt;«When moving our elPrep software away from Common Lisp, we evaluated C++, Go and Java as potential candidates, and Go turned out to provide the best balance between performance and memory use. We are still using Common Lisp for prototyping, and then translate to Go. These two languages are actually much more similar than it appears at first. […]»&lt;/p&gt;

&lt;p&gt;«This was primarily for the lack of good parallel, concurrent garbage collectors in Common Lisp implementations. The CL version of elPrep was actually still a tad faster than any of the C++, Go, or Java versions, but we had to work hard to avoid long GC pauses. elPrep allocates a lot of memory, and the pause time hurts a lot. We solved this by, basically, disabling the garbage collector, and reusing memory manually as much as possible, which turned the program into almost a manually memory-managed affair.»&lt;/p&gt;

&lt;p&gt;«Manual memory management became a huge burden because we wanted to add more and more components to the software, and then it becomes almost impossible to predict object lifetimes.»&lt;/p&gt;

&lt;p&gt;«We evaluated Go and Java for their concurrent, parallel GCs, and C++ for its reference counting. Interestingly, reference counting is often described as more efficient than GC, but in our case that’s not true: Because there is a huge object graph at some stage that needs to be deallocated, reference counting incurs more or less the same pause that a non-concurrent GC does. That’s why we don’t expect Rust to fare better here either.»&lt;/p&gt;

&lt;p&gt;«Again, we’re still prototyping in Common Lisp, which is a huge win, because this makes us much more productive.»&lt;/p&gt;

&lt;p&gt;«In my opinion, prototyping in Common Lisp, and then translating to a
different programming language for creating the final product, is a
perfectly valid professional use of Common Lisp. It’s useful to know
which programming languages may be good targets for such an approach. This is, of course, not ideal, because this can easily be
misunderstood as a statement that Common Lisp is not fit for
purpose. However, I don’t see it that way, and you cannot control
people’s perceptions. In our particular case, our manager is on board with this approach, and this allows us to pay for regular licenses for LispWorks. The
approach works really well for us.»&lt;/p&gt;

&lt;p&gt;Didier Verna:&lt;/p&gt;

&lt;p&gt;«I&amp;rsquo;d be curious to know if there are particularities in CL itself that make this difficult, or if it&amp;rsquo;s simply because there&amp;rsquo;s no manpower to improve the GCs we have currently.»&lt;/p&gt;

&lt;p&gt;Stelian Ionescu:&lt;/p&gt;

&lt;p&gt;«It&amp;rsquo;s strictly a lack of manpower. Most CL implementations have GCs that were state-of-the-art 25 years ago: they&amp;rsquo;re either mark-and-sweep or copying &amp;amp; generational, and have to perform all collection while application threads are paused (i.e. stop-the-world), hence the collection pauses that are proportional to the heap size.»&lt;/p&gt;

&lt;p&gt;«The newer GCs of Go and the JVM (ZGC and Shenandoah) are not generational and employ techniques such as pointer coloring and store/load barriers by instrumenting all object read/write operations instead of using virtual memory protection (which tends to have a non-indifferent performance penalty), and because they rely heavily on atomic operations to maintain heap consistency the stop-the-world phase is much shorter and only required to update the internal GC metadata.
The result is that instead of 99th percentile pauses of 10+ seconds that we see with QPX or other allocation-heavy applications, these newer GCs show 99th percentile pauses of &amp;lt; 10ms, and perhaps medians going from ~500ms to 2ms (YMMV).»&lt;/p&gt;

&lt;p&gt;«Here&amp;rsquo;s a pretty good description of the difference between the two new JVM collectors and how they compare to the older ones: &lt;a href=&#34;https://www.youtube.com/watch?v=WU_mqNBEacw.»&#34;&gt;https://www.youtube.com/watch?v=WU_mqNBEacw.»&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Martin Cracauer:&lt;/p&gt;

&lt;p&gt;«No, it&amp;rsquo;s as possible as in other languages. Some people don&amp;rsquo;t want to pay the overall performance penalty for concurrent GC (as in total CPU time/energy spent for any given piece of work).»&lt;/p&gt;

&lt;p&gt;«This particularly applies to applications that are query-based, and hence want to be as fast as possible in the non-GC part, and can GC between queries.  ITA&amp;rsquo;s QPX is an example (although they do desire concurrent GC for better monitoring in the production environment).»&lt;/p&gt;

&lt;p&gt;«Parallel GC is no problem and implemented.»&lt;/p&gt;

&lt;p&gt;Pascal Costanza:&lt;/p&gt;

&lt;p&gt;«Which CL implementations have a parallel GC?»&lt;/p&gt;

&lt;p&gt;Jeff Caldwell:&lt;/p&gt;

&lt;p&gt;«From Franz&amp;rsquo;s doc on Allegro CL: &lt;a href=&#34;https://franz.com/support/documentation/10.0/doc/gc.htm#multi-threading-2»&#34;&gt;https://franz.com/support/documentation/10.0/doc/gc.htm#multi-threading-2»&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Martin Cracauer:&lt;/p&gt;

&lt;p&gt;«Clasp (via Boehm GC and MPS).»&lt;/p&gt;

&lt;p&gt;«I thought SBCL was there, but I just checked, not yet.  I think Google
is pushing for a parallel GC instead, because of response times to
their production monitoring.»&lt;/p&gt;

&lt;p&gt;«Another untapped source of performance is userfaultfd(2) in the Linux kernel.  It allows those GCs that implement a write barrier using page protections SIGSEGV to use the faster userfaultfd interface instead (as opposed to those using a bitmap).  This won&amp;rsquo;t help concurrent GC, but parallel GC would benefit even more than single-thread GC because it uses faster system calls. Proof of concept is here: &lt;a href=&#34;https://www.cons.org/cracauer/cracauer-userfaultfd.html»&#34;&gt;https://www.cons.org/cracauer/cracauer-userfaultfd.html»&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t the latest incarnations of ECL use the Bohem GC?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Daniel Kochmański:&lt;/p&gt;

&lt;p&gt;«They do, we plan to resurrect the homegrown gc as an alternative though.»&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lisp Interview: more questions to CLPM author. Common Lisp at university for temporal reasoning and risk-bounded planning</title>
      <link>/blog/lisp-interview-more-questions-to-daewok-clpm-author/</link>
      <pubDate>Sun, 15 Nov 2020 08:22:59 +0100</pubDate>
      
      <guid>/blog/lisp-interview-more-questions-to-daewok-clpm-author/</guid>
      <description>

&lt;p&gt;Some days ago &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/jtla4m/common_lisp_package_manager_a_package_manager_for/&#34;&gt;on reddit/r/lisp&lt;/a&gt;,
we got to (re)discover CLPM, the Common Lisp Package Manager.&lt;/p&gt;

&lt;p&gt;Its author, Eric Timmons aka &lt;a href=&#34;https://github.com/daewok/&#34;&gt;daewok&lt;/a&gt;, was kind enough to give more context, and to answer some more questions of mine, about his use of Common Lisp in his university group.&lt;/p&gt;

&lt;p&gt;Below I&amp;rsquo;ll give an overview of CLPM, stress on how it differs from
Quicklisp, and then paste the interview.&lt;/p&gt;

&lt;p&gt;/Note/: it&amp;rsquo;s the same content as on reddit, but saved from oblivion!&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#clpm&#34;&gt;CLPM&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#context&#34;&gt;Context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#feature-set-and-comparison-to-quicklisp&#34;&gt;Feature set and comparison to Quicklisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#more-questions-to-eric-timmons---using-lisp-at-university-for-temporal-reasoning-and-risk-bounded-planning&#34;&gt;More questions to Eric Timmons - using Lisp at university for temporal reasoning and risk-bounded planning.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;clpm&#34;&gt;CLPM&lt;/h2&gt;

&lt;h3 id=&#34;context&#34;&gt;Context&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;CLPM author here. I&amp;rsquo;m so happy (and shocked!) that people have found CLPM, especially given how little advertising I&amp;rsquo;ve done for it! I&amp;rsquo;m a PhD student in a group that does a large amount of our coding in Common Lisp. A big part of why I wrote CLPM, for better or worse, is that my group has not done a great job at versioning or maintaining backward compatibility of our various libraries throughout the years. I&amp;rsquo;m a very applications focused person and it was incredibly frustrating when I needed to deploy some of our code that had worked in the past but found that it bit rotted. And then when I would eventually get everything rolled back to the correct point in time I had no way to release a fix that was no longer applicable on the master branch (normally because the relevant API no longer existed or had been modified in a non-backward compatible way). So I hoped that encouraging/requiring actual version numbers would help us better communicate and reason about our changes over time (and be able to release minor changes to older versions of the code) and the locking capabilities would help save us in situations like giving a demo on short notice.&lt;/p&gt;

&lt;p&gt;I use CLPM as my daily driver as do a couple of the other Lisp-heavy students. It&amp;rsquo;s been going well so far, but I was planning to convert and get feedback from a few more before attempting to spread CLPM beyond my group. That&amp;rsquo;s unfortunately taken a lot longer than I wanted due to COVID, my personal life taking more time than normal (no worries, it&amp;rsquo;s for good reasons!), and just general research related tasks continuing to pop up.&lt;/p&gt;

&lt;p&gt;Now that the cat&amp;rsquo;s out of the bag though, I&amp;rsquo;d be happy to hear any feedback on it! I&amp;rsquo;m especially interested in the perspectives of people outside my group since I&amp;rsquo;ve been holding their hand in getting it set up and explaining my reasoning/goals to them almost every step of the way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;feature-set-and-comparison-to-quicklisp&#34;&gt;Feature set and comparison to Quicklisp&lt;/h3&gt;

&lt;p&gt;CLPM&amp;rsquo;s &lt;a href=&#34;https://gitlab.common-lisp.net/clpm/clpm&#34;&gt;project page&lt;/a&gt; (here&amp;rsquo;s a non-official &lt;a href=&#34;https://github.com/lisp-mirror/clpm&#34;&gt;GitHub mirror&lt;/a&gt;, if that helps you browse the repository) lists the project goals. Here&amp;rsquo;s my comment and comparison to Quicklisp.&lt;/p&gt;

&lt;h4 id=&#34;support-and-encourage-explicitly-versioned-systems&#34;&gt;&lt;em&gt;Support and encourage explicitly versioned systems&lt;/em&gt;&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;When a package upgrade introduces regressions, we should be able to use an older version.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But, that is currently not possible with the Quicklisp client, we must refer to other tools (Qlot) or manual workarounds.&lt;/p&gt;

&lt;p&gt;CLPM allows to use monthly-based releases, just as Quicklisp and from Quicklisp, but it also started &lt;em&gt;a new source registry&lt;/em&gt; for Common Lisp libraries, which would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;allow to &lt;em&gt;precisely pin dependencies&lt;/em&gt;. It is possible to do so in ASDF, but this propriety is not used in Quicklisp (or barely, or not by most of the library authors, because Quicklisp comes as monthly distributions anyways).&lt;/li&gt;
&lt;li&gt;allow to get the library&amp;rsquo;s home URL, which surprisingly isn&amp;rsquo;t in Quicklisp&amp;rsquo;s metadata (last time I checked, I might be wrong). We have to look at the quicklisp-projects repository.&lt;/li&gt;
&lt;li&gt;it would enforce the libraries to be on version control. Currently Quicklisp also accepts source files (as archives).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;support-installing-multiple-package-versions-globally-and-locally&#34;&gt;&lt;em&gt;Support installing multiple package versions, globally and locally&lt;/em&gt;&lt;/h4&gt;

&lt;p&gt;CLPM allows to &lt;em&gt;manage dependencies per project&lt;/em&gt; (per directory), and globally. With Quicklisp, it&amp;rsquo;s only globally. Otherwise we must rely to Qlot, or load projects more manually.&lt;/p&gt;

&lt;p&gt;While I personally find the Quicklisp approach great, simple to use,
sufficient in most cases and a better default than always pinning
dependencies manually, comes a point in a software life when we need
project-local dependencies.&lt;/p&gt;

&lt;h4 id=&#34;support-ci-cd-workflows-ship-pre-built-binaries&#34;&gt;&lt;em&gt;Support CI/CD workflows - ship pre-built binaries&lt;/em&gt;&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;CLPM is distributed in both binary and source form&lt;/em&gt;. Source for hackers or people who want to use a different feature set and binary for quick and easy installation in other cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That&amp;rsquo;s simpler to install, to use on CI systems, or to make you software&amp;rsquo;s users install the dependencies.&lt;/p&gt;

&lt;p&gt;Currently we can use Roswell to install Quicklisp libraries (and software) from the command line, but its installation isn&amp;rsquo;t crystal straightforward or super fast either.&lt;/p&gt;

&lt;h4 id=&#34;minimize-footprint-in-development-images-and-deployments&#34;&gt;&lt;em&gt;Minimize footprint in development images and deployments&lt;/em&gt;&lt;/h4&gt;

&lt;p&gt;When you use CLPM and you build a binary of your program, the binary won&amp;rsquo;t contain CLPM (or only if you choose to). When we use Quicklisp, the built image contains Quicklisp (which can be very useful, I use it to live-reload running web apps).&lt;/p&gt;

&lt;h4 id=&#34;support-https&#34;&gt;&lt;em&gt;Support HTTPS&lt;/em&gt;&lt;/h4&gt;

&lt;p&gt;Quicklisp currently doesn&amp;rsquo;t download packages through HTTPS.&lt;/p&gt;

&lt;p&gt;Cryptographic signature verification is coming.&lt;/p&gt;

&lt;h2 id=&#34;more-questions-to-eric-timmons-using-lisp-at-university-for-temporal-reasoning-and-risk-bounded-planning&#34;&gt;More questions to Eric Timmons - using Lisp at university for temporal reasoning and risk-bounded planning.&lt;/h2&gt;

&lt;h3 id=&#34;what-are-you-using-cl-for-at-your-university&#34;&gt;What are you using CL for at your university?&lt;/h3&gt;

&lt;p&gt;My group&amp;rsquo;s bread and butter is in temporal reasoning and risk-bounded planning and execution (including both activity and path planning). I&amp;rsquo;m personally working on a high-level language for specifying robotic information gathering missions and an executive to plan and dispatch the missions. Language wise I think you could say it&amp;rsquo;s a stripped down Screamer when it comes to non-deterministic programming and constraints, coupled with parallel and sequential operators and the ability to temporally constrain the relative execution time of different events in the program. There&amp;rsquo;s a few more things, such as support for expressing PDDL-like operators, but that&amp;rsquo;s the 10,000 foot view.&lt;/p&gt;

&lt;p&gt;I mentioned I&amp;rsquo;m applications focused and a lot of that focus of late has been on mission planning for autonomous underwater vehicles. Unfortunately, most of our code is running off the vehicles, but we&amp;rsquo;re slowing moving more reasoning onboard.&lt;/p&gt;

&lt;h3 id=&#34;do-you-know-other-teams-in-your-university-that-are-using-cl-or-a-lisp-like-language&#34;&gt;Do you know other teams in your university that are using CL? (or, a lisp-like language?)&lt;/h3&gt;

&lt;p&gt;I know other groups do but I&amp;rsquo;m not sure of the details, unfortunately.&lt;/p&gt;

&lt;h3 id=&#34;so-why-cl-does-it-have-a-killer-feature-that-make-your-group-use-it-it-doesn-t-have-to-have-one-though&#34;&gt;So, why CL? Does it have a killer feature that make your group use it? (it doesn&amp;rsquo;t have to have one though!)&lt;/h3&gt;

&lt;p&gt;Ha, we started using CL long before I joined the group. From what I hear, it was originally mostly for practical reasons: it&amp;rsquo;s the language my group&amp;rsquo;s PI [Principal Investigator] knows the best and he needed to be able to hop onto any given project as students cycled on and off. But with respect to my personal research, I think CL is the best language for it. You can&amp;rsquo;t beat its macros for defining DSLs and I have a lot of DSLs both in my high level language (along with some MOP code!) and the planner. Something my advisor said to me about CL that really stuck with me is that it is a fantastic language to let you write a new language for the problem you want to solve, and specifying the problem is more than half the battle in solving it.&lt;/p&gt;

&lt;h3 id=&#34;are-there-downsides-do-you-have-difficulties-in-certain-areas-formation&#34;&gt;Are there downsides, do you have difficulties in certain areas? (formation?)&lt;/h3&gt;

&lt;p&gt;The biggest downside for us is that students rarely come into the group with CL experience and in rare cases some students refuse to really dive into our Lisp code and stick with something they&amp;rsquo;re more familiar with (such as Python) and end up reinventing poor facsimiles of things that exist.&lt;/p&gt;

&lt;p&gt;Ignoring that particular issue, using CL does add a non-trivial amount of time to on-boarding new students. Then beyond that, we had the aforementioned issues with not versioning correctly and not maintaining backward compatibility. While that&amp;rsquo;s really, at it&amp;rsquo;s core, a social issue that would exist regardless of language (and is hard to avoid given the natural turn-over rate of students), the lack of a package manager with features similar to those provided in the languages students come in knowing these days certainly didn&amp;rsquo;t help.&lt;/p&gt;

&lt;h3 id=&#34;how-did-you-personally-start-with-cl&#34;&gt;How did you personally start with CL?&lt;/h3&gt;

&lt;p&gt;I started with CL when I joined this group. I was given a URL to Practical Common Lisp and off I went. I kind of fell down the rabbit hole at some point and spent more time learning about the language than doing research (oops), but I think that&amp;rsquo;s paid off by this point as I can make CL do nearly anything I can think of. The first draft (or several&amp;hellip;) of my code may not be pretty, but they&amp;rsquo;ll work, get the job done, and I can continue working on abstractions and mini-DSLs to my heart&amp;rsquo;s content whenever I need to make things more clear or performant.&lt;/p&gt;

&lt;h3 id=&#34;can-you-tell-us-more-about-your-software-stack-implementations-most-loved-libraries-deployment-story-docker-interface-with-other-tools-monitoring&#34;&gt;Can you tell us more about your software stack? (implementations, most loved libraries, deployment story (docker?), interface with other tools (monitoring?)…)&lt;/h3&gt;

&lt;p&gt;We largely use SBCL these days. I routinely try to test on the other big Free implementations as well (ABCL, CCL, ECL) both out of a desire to be portable for portability sake and to make the code more widely useful if we ever get around to sharing it beyond our collaborators more (which I am cautiously hopeful will happen). I particularly love Hunchentoot, Drakma, basically anything from Edi Weitz, log4cl, closer-mop, and, of course, CFFI.&lt;/p&gt;

&lt;p&gt;We do a lot of our deployment with Docker (which is why I&amp;rsquo;m currently maintaining a number of CL related Docker images). I occasionally deploy things using Kubernetes (e.g., when we want to deploy our planners as a service for the students in my advisor&amp;rsquo;s classes to use). I personally love Kubernetes, but I&amp;rsquo;ve found that it&amp;rsquo;s difficult to get other students up to speed on it (let alone use it!) because it&amp;rsquo;s just one more set of things for them to learn when their focus is on graduating.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re also working on getting more of our code running on ARM64 processors, since that&amp;rsquo;s largely what we have available to us for low-power robots. That&amp;rsquo;s proving to be a bit of a challenge, unfortunately because SBCL is fairly memory hungry and our algorithms are also inherently memory hungry. But in the end I think it&amp;rsquo;ll be fine as it&amp;rsquo;s a driving force to get us to do only the necessary reasoning onboard.&lt;/p&gt;

&lt;p&gt;We don&amp;rsquo;t have any great stories with regard to interfaces with other tools, but I have been meaning to pick up prometheus.cl and give it a try.&lt;/p&gt;

&lt;h3 id=&#34;anything-more-to-add&#34;&gt;Anything more to add?&lt;/h3&gt;

&lt;p&gt;CL is awesome! Nothing else comes to mind right now.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Thanks again Eric.&lt;/p&gt;

&lt;hr /&gt;

&lt;div style=&#39;margin-top:80px&#39;&gt;
&lt;a href=&#39;https://ko-fi.com/K3K828W0V&#39; target=&#39;_blank&#39;&gt;&lt;img height=&#39;36&#39; style=&#39;border:0px;height:36px;&#39; src=&#39;https://cdn.ko-fi.com/cdn/kofi2.png?v=2&#39; border=&#39;0&#39; alt=&#39;ko-fi button&#39; title=&#39;Yes, it helps (no fixed nor big income today) and money goes to Lisp development, for me or contributors. Thanks!&#39;/&gt;&lt;/a&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>You can buy a preview of the Common Lisp Cookbook in ePub</title>
      <link>/blog/you-can-buy-a-preview-of-the-common-lisp-cookbook-in-epub/</link>
      <pubDate>Fri, 13 Nov 2020 22:48:15 +0100</pubDate>
      
      <guid>/blog/you-can-buy-a-preview-of-the-common-lisp-cookbook-in-epub/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://storage.ko-fi.com/cdn/useruploads/display/39a60d12-fa99-409d-873f-853318f811d8_orly-cover.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See here: &lt;a href=&#34;https://ko-fi.com/s/01fee22a32&#34;&gt;https://ko-fi.com/s/01fee22a32&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let me try something: I propose you here to buy the ePub, even though it is meant to be available for free.&lt;/p&gt;

&lt;p&gt;I contributed quite a lot to the Cookbook and I found since the
beginning that having an EPUB and/or a PDF version would be very
useful. Some years later, nobody did it, and I finally wrote a script
to bundle all the pages together and generate an ePub, and then a
PDF. It isn&amp;rsquo;t finished though, it needs more editing, and it would
also be great to write a proper LaTeX style for the PDF. As I have one
version on disk, I thought on giving potential supporters the
opportunity to read it and fund the remaining work, or simply give a sign of
encouragement. It&amp;rsquo;s also the opportunity for me to try this new Ko-fi
feature, and to practice speaking about financial support…&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s turn it another way: if you support me, here&amp;rsquo;s a reward for you, an exclusivity.
And in any case, hold on, this ePub will eventually be available for everybody.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;ps: About money: yes, it does a difference right now, because I don&amp;rsquo;t
have a fixed, nor big, income. I am trying to live on my free software
activities. I have a few clients, but not enough, so I&amp;rsquo;m trying to
diversify and get some earnings from my Lisp work. I even pay lisp
contributors to write free software (we are currently adding Stripe
payments to a web application. When it&amp;rsquo;s done, you&amp;rsquo;ll know everything
about it). So, the money has an impact.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Composing queries with Mito, or doing without Django lazy querysets and Q objects</title>
      <link>/blog/composing-queries-with-mito-aka-replacing-lazy-querysets-and-q-objects/</link>
      <pubDate>Thu, 24 Sep 2020 18:15:44 +0200</pubDate>
      
      <guid>/blog/composing-queries-with-mito-aka-replacing-lazy-querysets-and-q-objects/</guid>
      <description>

&lt;p&gt;When I didn&amp;rsquo;t know Lisp at all, I skimmed at CLSQL&amp;rsquo;s and Mito&amp;rsquo;s
documentation and I didn&amp;rsquo;t find a mention of &amp;ldquo;lazy&amp;rdquo;, &amp;ldquo;querysets&amp;rdquo; (a
Django term!) nor a mention of any means to compose queries. I had no
idea how I would replace &lt;code&gt;querysets&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt; objects and the many
functions for DB queries that were being added into newer Django
versions. I concluded that the Lisp ecosystem was lagging behind.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-solution&#34;&gt;The solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#last-words&#34;&gt;Last words&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;p&gt;Then I began to understand. And today I got the chance to rewrite a
Django query involving querysets and &lt;code&gt;Q&lt;/code&gt; objects, using regular
Lisp. All you have to know is back-quote and comma.&lt;/p&gt;

&lt;p&gt;We implement a simple search into a DB. The user enters one or more
words and we search against the &lt;code&gt;title&lt;/code&gt; and the &lt;code&gt;authors&lt;/code&gt; fields. We
want to match all words, but each can be either in the title, either
in the authors field.&lt;/p&gt;

&lt;p&gt;Considering we have two products:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-ascii&#34;&gt;1 - The Lisp Condition System - phoe
2 - Implementing a blockchain in Lisp - F. Drummer
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then searching for &amp;ldquo;lisp cond&amp;rdquo; must return one result. DWIM.&lt;/p&gt;

&lt;p&gt;In Python, we must use &lt;code&gt;Q&lt;/code&gt; objects to &amp;ldquo;OR&amp;rdquo; the terms with &lt;code&gt;|&lt;/code&gt; (you can&amp;rsquo;t use &lt;code&gt;|&lt;/code&gt; without &lt;code&gt;Q&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;products = firstquery()
for word in words:
    products = products.objects.filter(Q(title__icontains=word) |
                                       Q(authors__name__icontains=word))\
                               .distinct()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The promise of &lt;code&gt;filter&lt;/code&gt; is to be lazy, so when we chain them the ORM
 constructs one single SQL query.&lt;/p&gt;

&lt;p&gt;So what does this query yield as SQL? Funnily, I didn&amp;rsquo;t find a
built-in way to get the generated SQL and I had to use a third-party
library. Mmh, I could use special logging. The fact is, we are far
from SQL here (and, with the experience, it is NOT a good thing).&lt;/p&gt;

&lt;p&gt;It looks like this (searching &amp;ldquo;hommes femmes&amp;rdquo; in our test DB):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sql&#34;&gt;       SELECT DISTINCT ... FROM &amp;quot;product&amp;quot; LEFT OUTER JOIN ...
       WHERE
       ((&amp;quot;product&amp;quot;.&amp;quot;title&amp;quot; LIKE %hommes% ESCAPE &#39;\&#39;
         OR &amp;quot;author&amp;quot;.&amp;quot;name&amp;quot; LIKE %hommes% ESCAPE &#39;\&#39;)
        AND
         (&amp;quot;product&amp;quot;.&amp;quot;title&amp;quot; LIKE %femmes% ESCAPE &#39;\&#39;
         OR T5.&amp;quot;name&amp;quot; LIKE %femmes% ESCAPE &#39;\&#39;))
       ORDER BY &amp;quot;product&amp;quot;.&amp;quot;created&amp;quot; DESC
       LIMIT 3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Does that look complicated? Does that need alien &amp;ldquo;Q objects&amp;rdquo;?! It&amp;rsquo;s just a AND around two OR:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-ascii&#34;&gt;   title like keyword 1 OR author like keyword 1
AND
   title like keyword 2 OR author like keyword 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Mito is the high-level library, and we compose queries with SXQL. I
already had a little query that worked with one keyword:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun find-product (&amp;amp;key query (order :asc))
  (mito:select-dao &#39;product
    (when query
      (sxql:where (:or (:like :title (str:concat &amp;quot;%&amp;quot; query &amp;quot;%&amp;quot;))
                       (:like :authors (str:concat &amp;quot;%&amp;quot; query &amp;quot;%&amp;quot;)))))
    (sxql:order-by `(,order :created-at))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If &lt;code&gt;:query&lt;/code&gt; is given, we filter the search. If not, the &lt;code&gt;when&lt;/code&gt; is not executed and we return all products.&lt;/p&gt;

&lt;p&gt;So what we need to do is iterate over the keywords, produce as many OR
and wrap them with a AND. We want something like that (we can try in the REPL):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(:AND
 (:OR (:LIKE :TITLE &amp;quot;%word1%&amp;quot;)
      (:LIKE :AUTHORS &amp;quot;%word1%&amp;quot;))
 (:OR (:LIKE :TITLE &amp;quot;%word2%&amp;quot;)
      (:LIKE :AUTHORS &amp;quot;%word2%&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;h2 id=&#34;the-solution&#34;&gt;The solution&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(sxql:where
 `(:and   ;; &amp;lt;-- backquote
   ,@(loop for word in (str:words query)  ;; &amp;lt;-- comma-splice
        :collect `(:or (:like :title ,(str:concat &amp;quot;%&amp;quot; word &amp;quot;%&amp;quot;))  ;; &amp;lt;-- backquote, comma
                       (:like :authors ,(str:concat &amp;quot;%&amp;quot; word &amp;quot;%&amp;quot;))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(using &lt;code&gt;(ql:quickload &amp;quot;str&amp;quot;)&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Pay attention to &lt;code&gt;,@&lt;/code&gt; (comma-splice). Without it, we get a bad level
of nesting and two parenthesis before the :OR. We would get a list of
clauses, instead of each clause individually. You can try in the REPL.&lt;/p&gt;

&lt;p&gt;Note: if you are uneasy with back-quote and comma, see: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/macros.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/macros.html&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;last-words&#34;&gt;Last words&lt;/h2&gt;

&lt;p&gt;Django&amp;rsquo;s &lt;code&gt;filter&lt;/code&gt; &lt;a href=&#34;https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/&#34;&gt;is similar to using a
When&lt;/a&gt;,
which we were already using on the Lisp side without knowing it was
anything special. &amp;ldquo;Q objects&amp;rdquo; are easy to replace. So, Python and
Django might be easy to getting started with (or it is your feeling,
because you must learn the special syntax and its limitations, I bet
you had some &amp;ldquo;WTF?!&amp;rdquo; moments), but comes a time when your application
grows that you pay the price of being far from SQL (not counting the
maintenance cost).&lt;/p&gt;

&lt;p&gt;With Mito and SXQL, it&amp;rsquo;s all regular Lisp, we are closer to the metal,
the only limitation being to know the language, and a bit of SQL.&lt;/p&gt;

&lt;p&gt;So we have a great example of why some Common Lisp libraries have a
surprisingly low number of commits. You know, that little voice in
your head that wonders if a library is finished or active. The author
might not need to develop feature X, thanks to Lisp&amp;rsquo;s
expressiveness. Likewise, many questions don&amp;rsquo;t need to be asked or
upvoted on Stack-Overflow. Though I should have asked years ago.&lt;/p&gt;

&lt;hr /&gt;

&lt;ul&gt;
&lt;li&gt;getting started with a DB: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/databases.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;more DB choices: &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#database&#34;&gt;https://github.com/CodyReichert/awesome-cl#database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;div&gt;
You like what I&#39;m doing?
&lt;br/&gt;

&lt;a href=&#39;https://ko-fi.com/K3K828W0V&#39; target=&#39;_blank&#39;&gt;&lt;img height=&#39;36&#39; style=&#39;border:0px;height:36px;&#39; src=&#39;https://cdn.ko-fi.com/cdn/kofi2.png?v=2&#39; border=&#39;0&#39; alt=&#39;You can buy Me a Coffee at ko-fi.com&#39; title=&#39;My hidden plan is to make Common Lisp popular again. No fixed income ATM, and I want to do more, so it helps. Thanks!&#39;/&gt;&lt;/a&gt;

&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>How are Lisp REPLs different from Python or Ruby REPLs ? (Hackernews, 2020)</title>
      <link>/blog/how-are-lisp-repls-different-from-python-or-ruby-repls/</link>
      <pubDate>Tue, 14 Jul 2020 16:11:43 +0200</pubDate>
      
      <guid>/blog/how-are-lisp-repls-different-from-python-or-ruby-repls/</guid>
      <description>&lt;p&gt;Mikelevins, &lt;a href=&#34;https://news.ycombinator.com/item?id=23811382&#34;&gt;https://news.ycombinator.com/item?id=23811382&lt;/a&gt;, July 2020&lt;/p&gt;

&lt;p&gt;(some more comments on &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/hqesvp/explaining_the_advantages_of_the_repl/&#34;&gt;https://www.reddit.com/r/lisp/comments/hqesvp/explaining_the_advantages_of_the_repl/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;(on terminology: we should maybe call Python&amp;rsquo;s &amp;ldquo;REPL&amp;rdquo; a &lt;em&gt;shell&lt;/em&gt;, and put emphasis on &lt;em&gt;image-based development&lt;/em&gt;, instead of only saying REPL, for Lisp)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I&amp;rsquo;ve answered similar questions several times over the past few years, but I don&amp;rsquo;t mind repeating myself. It offers me a glimmer of hope that my preferred way of working may not fade away, after all.&lt;/p&gt;

&lt;p&gt;Consider the standard Common Lisp generic function &lt;code&gt;UPDATE-INSTANCE-FOR-REDEFINED-CLASS&lt;/code&gt; (&lt;a href=&#34;http://clhs.lisp.se/Body/f_upda_1.htm&#34;&gt;http://clhs.lisp.se/Body/f_upda_1.htm&lt;/a&gt;). It reinitializes an object when Lisp detects that the object&amp;rsquo;s class definition has changed.&lt;/p&gt;

&lt;p&gt;Ask yourself this: who would call such a function? Why would anyone ever invent it? Not only did someone invent it, a committee of some of the world&amp;rsquo;s smartest and most experienced Lisp programmers wrote it into the ANSI standard for the language. What were they up to?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UPDATE-INSTANCE-FOR-REDEFINED-CLASS&lt;/code&gt; is not a weird anomaly; it&amp;rsquo;s part of a carefully-considered set of features and protocols designed to support a specific style of programming. The Lisp runtime calls it for you automatically when it touches an object whose class definition has changed.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;ve defined a method specialized for it, then Lisp executes that method to rebuild the touched instance as if it had originally been instantiated from the class&amp;rsquo;s new definition, and then your program goes its merry way. If you didn&amp;rsquo;t specialize &lt;code&gt;UPDATE-INSTANCE-FOR-REDEFINED-CLASS&lt;/code&gt; for this case, then the Lisp drops you into a breakloop.&lt;/p&gt;

&lt;p&gt;A breakloop is an interactive repl with full access to all of the runtime&amp;rsquo;s memory and all of the language&amp;rsquo;s features, including visibility into the whole call stack that landed you in the breakloop. You can wander up and down the call stack, inspect anything in the runtime, edit bindings, redefine types and functions, and resume execution either at the point of control where the breakloop started, or at any other point for which the breakloop exposes a restart.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UPDATE-INSTANCE-FOR-REDEFINED-CLASS&lt;/code&gt; is not the weird fever dream of a confused eccentric. It&amp;rsquo;s part of a purposeful system design intended to support a style of programming in which you build a program by interacting with a live runtime and teach it, interaction-by-interaction, how to be the program you want, while it runs.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a particular example of a general approach to programming best exemplified by these old systems. That general approach is the answer to your question: &amp;ldquo;Can someone knowledgeable explain how are lisp REPLs different from Python / Ruby REPLs? What is the differentiating point of REPL driven development?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;The differentiating point is that the entire language and system is thoughtfully designed from the ground up with the assumption that you&amp;rsquo;re going to be changing your work in progress while it runs, and that you should be able to change absolutely anything about it as it runs and have a reasonable expectation that it will continue to work while you do it.&lt;/p&gt;

&lt;p&gt;I like to call this style of programming &amp;ldquo;programming as teaching&amp;rdquo;, and distinguish it from the much more widespread &amp;ldquo;programming as carpentry&amp;rdquo;, in which the programmer is, metaphorically speaking, at a workbench banging together artifacts and assembling them to see how they turn out.&lt;/p&gt;

&lt;p&gt;To be clear, I do not claim that the teaching approach is objectively better than the carpentry approach. I claim only that I, personally, am happier and measurably more productive using the teaching approach. I know that some other programmers report the same thing, and I suspect that if the teaching style of programming were more widely known, then there would be more programmers who prefer it.&lt;/p&gt;

&lt;p&gt;There are several sibling comments that assert that any language can be made to support repl-driven programming, or that offer various languages and systems as examples of repl-driven programming. I&amp;rsquo;m sure that&amp;rsquo;s all true, for some relatively restricted version of repl-driven programming, but the gold standard in repl-driven programming is programming as teaching in the style of old-fashioned Lisp and Smalltalk systems. These old systems offer amenities that the younger alternatives touted here do not match. I want more people to be aware of what they&amp;rsquo;re missing.&lt;/p&gt;

&lt;p&gt;Starting in the 1980s, I grew accustomed to systems that could start from cold in about a second, presenting to me a complete interactive development environment with all tools preloaded and ready to work, with the whole dynamic environment of my work in progress in the same state it was in the last time I was working with it. Moreover, I was accustomed to being able to take a single file from one machine to another to reproduce that same whole working environment equally quickly and easily on the new machine.&lt;/p&gt;

&lt;p&gt;I could save the entire dynamic state of the running system to an image file, a serialized version of the running system&amp;rsquo;s memory. I could later start up the system with that image file and be exactly where I was when I saved the image, right down to the positions and contents of all the open windows. I could save an image showing some bug or some strange behavior and give it to a colleague so that they could see it, too, and interact with the restored dynamic state to debug it.&lt;/p&gt;

&lt;p&gt;I enjoyed comprehensive whole-system reflection that enabled me to view and edit absolutely everything in the running system while it ran. I could inspect absolutely everything, including the development environment and all its tools, interactively change any variable or field value, redefine any type or function, and continue to work with the changed system without stopping and restarting. (Obviously, if I made a bad change I might break the system, but remember, I could kill it and get back to where I started in a second or so).&lt;/p&gt;

&lt;p&gt;I could start some process running&amp;ndash;perhaps a 3D animation in a game, or a discrete-event simulation, or whatever&amp;ndash;and change any values or definitions I liked to see what changed in the running process, without stopping the process to rebuild. For example, I could tell a rotating copper cube to become a glass icosahedron and reasonably expect to see my changes immediately reflected in the running program. This property is invaluable not only in games, simulations, and any kind of work with a visual-design component, but also in any kind of exploratory programming, where you&amp;rsquo;re constructing data structures and evaluating expressions interactively to test your ideas.&lt;/p&gt;

&lt;p&gt;Similarly, I could build some speculative data structure to explore an idea, and define some functions to operate on it. I could evaluate those expressions to see their results or to change the example structure. I could inspect the structure interactively and edit it in place if I think something different would work better. If I think a problem is caused by some structure or value in it, I could use the inspector to change it and see. If I thought one my my functions was doing something I didn&amp;rsquo;t expect, I could insert a call to break, to activate a repl from inside the function call that would enable me to inspect and edit the data structure, redefine the function, and continue from there.&lt;/p&gt;

&lt;p&gt;Anything the development system could do, I could do by typing an expression into the repl. As an example, nowadays you can still rebuild the whole Clozure Common Lisp environment from the ground up by typing (rebuild-ccl :full t).&lt;/p&gt;

&lt;p&gt;The point is not that I would want to rebuld my Lisp from the repl all the time. The point is that the repl doesn&amp;rsquo;t impose any aribtrary boundaries on what I can do. If the language and development environment can do it, I can do it from the repl. This is one of the properties that distinguishes the whole-system interactive design of these old tools from the more limited repls offered by newer ones. In pretty much every repl I&amp;rsquo;ve used other than old-style Lisps and Smalltalks I&amp;rsquo;m all the time stumbling over things you can&amp;rsquo;t do from the repl.&lt;/p&gt;

&lt;p&gt;I mentioned breakloops above. Their absence in younger languages and tools seem to me like some sort of sin, like we&amp;rsquo;re tragically abandoning some of the best lessons of the past. Few newer development systems have them, but they&amp;rsquo;re incredibly useful&amp;ndash;at least if the language runtime is designed to properly support interactive programming.&lt;/p&gt;

&lt;p&gt;A breakloop is a repl with all of the same affordances of the normal repl, but extended with all of the dynamic state of the control path that invoked the breakloop. If an error or an intentional call to break triggers a breakloop somewhere deep in a stack of recursive function calls, you get a repl that can see every frame of that stack, and every variable and value lexically accessible from it. You can browse all of that whole, change values, and redefine functions and types. You can resume execution at your leisure, and any changes you made in the breakloop will be visible in the resumed computation just as if that&amp;rsquo;s how things were originally.&lt;/p&gt;

&lt;p&gt;Proper breakloops don&amp;rsquo;t just improve error messages; they replace them wholesale with an entire species of programming that lays the whole dynamic state of the system out on the table for you to examine and modify while the program continues to run.&lt;/p&gt;

&lt;p&gt;Moreover, everything I just described about breakloops can also be automated. These old systems provide not only interactive tools for rummaging through the dynamic state of a suspended computation, but also APIs for handling them under program control. For example, you can wrap an arbitrary function call in condition handlers that will either drop you into a breakloop and enable you to vivisect the program state, or consult the dynamic state and compute which of several restarts to activate in order to transfer control to a path of your choosing.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m banging up against HN&amp;rsquo;s length limit, but the above, I hope, goes some way toward answering to your question.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Looking for a Lisp Web Developer (not a real job, but nearly)</title>
      <link>/blog/looking-for-a-lisp-web-developer/</link>
      <pubDate>Fri, 05 Jun 2020 21:38:01 +0200</pubDate>
      
      <guid>/blog/looking-for-a-lisp-web-developer/</guid>
      <description>&lt;p&gt;Dear lispers,&lt;/p&gt;

&lt;p&gt;I decided that I can not develop three projects in parallel fast enough, so I&amp;rsquo;m seeking for a fellow programmer to join the effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer: this is not a real position, but there is a little budget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I recently presented my &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/a-free-software-for-bookshops-to-show-their-catalogue-online/&#34;&gt;online catalogue for bookshops&lt;/a&gt;. You will work on something very similar, but bigger. I need help to re-write the existing free software for bookshops in Common Lisp. The existing one is in Python. I have a prototype of the new CL one.&lt;/p&gt;

&lt;p&gt;The software specifications are here and are good. We wrote them years
ago by consulting people selling books, and we now grow on our
experience acquired developing the first Python app as well as on the
feedback gathered from clients. The challenge is to build a
maintainable, fast, bug-free, easily-deployable application with an
user interface that answers the clients&amp;rsquo; needs.&lt;/p&gt;

&lt;p&gt;I ask you to have some experience in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common Lisp&lt;/li&gt;
&lt;li&gt;the web: HTML, CSS, web browser API&lt;/li&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should also have a sufficiently good english to speak with me (a non-native speaker).&lt;/p&gt;

&lt;p&gt;I would have tasks for you in June and July, nothing in August, and
hopefully more in September and onwards.&lt;/p&gt;

&lt;p&gt;Bonus points include, in no particular order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;acquaintance with JavaScript, with a JS framework (preferably Vuejs)&lt;/li&gt;
&lt;li&gt;good HTML&amp;amp;CSS design skills&lt;/li&gt;
&lt;li&gt;you speak french&lt;/li&gt;
&lt;li&gt;you have a good english, or good communication skills in your mother tongue&lt;/li&gt;
&lt;li&gt;good backend and &amp;ldquo;devops&amp;rdquo; experience&lt;/li&gt;
&lt;li&gt;Python experience to install and study an existing project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this appeals to you, please email me at &lt;code&gt;(reverse
&amp;quot;gro.zliam@leradniv&amp;quot;)&lt;/code&gt; and indicate roughly how you stand in these
points, your availability in June, during the upcoming two weeks
for a meeting, and we&amp;rsquo;ll speak further.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A free software for bookshops to show their catalogue online</title>
      <link>/blog/a-free-software-for-bookshops-to-show-their-catalogue-online/</link>
      <pubDate>Sat, 30 May 2020 13:15:47 +0200</pubDate>
      
      <guid>/blog/a-free-software-for-bookshops-to-show-their-catalogue-online/</guid>
      <description>

&lt;p&gt;I wrote a free software for bookshops to publish their catalogue
online. Clients can now browse the available books and order them. It
is enough generic so we can show other products too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://abstock.gitlab.io/#/en/&#34;&gt;https://abstock.gitlab.io/#/en/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;sources and bug tracker: &lt;a href=&#34;https://gitlab.com/vindarel/abstock&#34;&gt;https://gitlab.com/vindarel/abstock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github mirror: &lt;a href=&#34;https://github.com/vindarel/ABStock&#34;&gt;https://github.com/vindarel/ABStock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://frama.link/syVBKWPw&#34;&gt;the demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;rsquo;s how a search result looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://abstock.gitlab.io/search.png&#34; style=&#34;max-width: 100%&#34;/&gt;&lt;/p&gt;

&lt;h1 id=&#34;features&#34;&gt;Features&lt;/h1&gt;

&lt;p&gt;The website is made generic enough for different clients, and is made
totally hackable with pre- and post- configuration files that load
your Lisp logic.&lt;/p&gt;

&lt;p&gt;By default we get the following pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the welcome screen, with:

&lt;ul&gt;
&lt;li&gt;the bookshop&amp;rsquo;s information,&lt;/li&gt;
&lt;li&gt;the search form. We can search by title, authors, publisher, shelf and ISBN(s).&lt;/li&gt;
&lt;li&gt;a random pre-selection of the books to showcase, if enabled.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;an optional special page to showcase a selection of books or other products.&lt;/li&gt;
&lt;li&gt;in the search results page, visitors can add a book to their shopping basket.&lt;/li&gt;
&lt;li&gt;and in the basket page, they find a confirmation form, which sends
the command by email to the shop owner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are obvious TODOs, that could be shocking by their absence, but
that I actually don&amp;rsquo;t need yet, so they&amp;rsquo;ll come right in time :)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;online payment&lt;/li&gt;
&lt;li&gt;admin page

&lt;ul&gt;
&lt;li&gt;simple stats (they are brought in with the email provider, and with Matomo statistics)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;i18n, remove a still few hardcoded words&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;data&#34;&gt;Data&lt;/h2&gt;

&lt;p&gt;ABStock connects by default to the &lt;a href=&#34;http://abelujo.cc/en/&#34;&gt;Abelujo&lt;/a&gt;
database. Abelujo is a free software for bookshops that I also
develop. Booksellers use it for their daily work, registering and
selling books.&lt;/p&gt;

&lt;p&gt;But we can define our own products. The current possibility is
to use a &lt;code&gt;cards.txt&lt;/code&gt; file. Each block expects a &lt;code&gt;title&lt;/code&gt;, and that&amp;rsquo;s
the only mandatory field. Other recognized fields are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;((:|id| integer)
 :|title|
 :|cover|
 :|isbn|
 :|price|
 :|author|
 :|publisher|
 :|date_publication|
 :|date-publication|
 :|shelf|
 :|shelf_id|
 :|details-url|
 :|summary|
 :|quantity|
 :|repr|
 :|repr2|)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can define other fields, like &lt;code&gt;likes&lt;/code&gt; below, which is
actually unused in the application.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[…]

title: Programming Algorithms
author: Vsevolod Domkin
cover: https://d2sofvawe08yqg.cloudfront.net/progalgs/hero?1586867024
details-url: https://leanpub.com/progalgs
shelf: programming
shelf_id: 99
publisher: Leanpub
price: 15
likes: 5

title: Cats
author: mother cat
cover: https://gitlab.com/abstock/abstock.gitlab.io/-/raw/master/logo.png
details-url: https://gitlab.com/abstock/abstock.gitlab.io/-/blob/master/logo.png
shelf: nature
shelf_id: 98
publisher: nature
price: 5
likes: 100

title: Screwdriver
author:
cover: https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.jGOb7dVL1oA9VDzNVPDPpwAAAA%26pid%3DApi&amp;amp;f=1
details-url:
shelf: craftmanship
shelf_id: 97
publisher:
price: 10
likes: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(yes there&amp;rsquo;s a little redundancy with shelf and shelf_id to fix)&lt;/p&gt;

&lt;p&gt;That gives:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://gitlab.com/vindarel/abstock/-/raw/master/other-data.png&#34; style=&#34;max-width: 100%&#34;/&gt;&lt;/p&gt;

&lt;p&gt;We could very well load a JSON, a CSV or another database when the need arises.&lt;/p&gt;

&lt;p&gt;For now, we think the text loader is enough for you to define your
products and try the application.&lt;/p&gt;

&lt;p&gt;It is also very easy to host, and in doing so &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/&#34;&gt;one can realize that to live-reload his Lisp web app is straighforward and very convenient&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;context&#34;&gt;Context&lt;/h1&gt;

&lt;p&gt;I shipped the app the second month of our lockdown period for the
client I was working for at that moment, and no need to say it turned
100% helpful. Amazon had hell of an activity, and french alternatives
for booksellers (such as lalibrairie.com or placedeslibraires.fr)
either had stopped, either couldn&amp;rsquo;t accept new registrations. So we
were left alone, and we did that. His clients were happy, they started
passing orders, he organized collection schedules. This happened in a
small rural village, where the inhabitants are happy to have, at
least, a (nice) bookshop in their village.&lt;/p&gt;

&lt;h1 id=&#34;paying-one-s-rent-with-lisp&#34;&gt;Paying one&amp;rsquo;s rent with Lisp&lt;/h1&gt;

&lt;p&gt;So yes, I paid my rent with Common Lisp again \o/ And you see, the
software is a classical web app. I could have made it with Python or
another language that has a web server and a templating library. As I
defended before, the app doesn&amp;rsquo;t exist thanks to CL&amp;rsquo;s super powers. CL
had no particular advantages for this kind of web app, but no
disavantages either: it has a good web framework, a good templating
library that I liked a lot (Djula: defining custom filters was a
breeze), a good SQL wrapper, and that&amp;rsquo;s all I asked. &lt;em&gt;I&lt;/em&gt; use CL&amp;rsquo;s
super powers during development and deployment. Clients wouldn&amp;rsquo;t see
the difference… or would they?&lt;/p&gt;

&lt;p&gt;Actually, CL has advantages &lt;em&gt;overall&lt;/em&gt;: development speed, ease of
deployment, ease of hot-reload, ease to use the language features to
bypass a library&amp;rsquo;s limitation (easy-routes had no built-in to
translate a route URL, but it turned possible with a reader macro)…
not mentioning ease of maintenance in time, speed, etc.&lt;/p&gt;

&lt;p&gt;One production bug I had was due to (me apart for not testing enough)
&lt;code&gt;(= 3 nil)&lt;/code&gt; throwing an error, so you must had prior checks (or, I
just realize, use &lt;code&gt;equalp&lt;/code&gt;?). My Sentry dashboard is empty anyways.&lt;/p&gt;

&lt;h1 id=&#34;final-words-with-bonus&#34;&gt;Final words (with bonus)&lt;/h1&gt;

&lt;p&gt;The Big Plan is to Rewrite It (the other software) In Lisp, and the
project just moved from R&amp;amp;D to POW… stay tuned, particularly if you
don&amp;rsquo;t know what to do in june and july, I might have a small budget
for a helping hand.&lt;/p&gt;

&lt;hr /&gt;

&lt;table&gt;
    &lt;tr&gt;
      &lt;td&gt;
&lt;a href=&#34;https://www.patreon.com/bePatron?u=35783903&#34; data-patreon-widget-type=&#34;become-patron-button&#34;&gt;Become a Patron!&lt;/a&gt;&lt;script async src=&#34;https://c6.patreon.com/becomePatronButton.bundle.js&#34;&gt;&lt;/script&gt;
      &lt;/td&gt;

      &lt;td style=&#34;padding-left: 1em&#34;&gt;
&lt;script src=&#34;https://liberapay.com/vindarel/widgets/button.js&#34;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href=&#34;https://liberapay.com/vindarel/donate&#34;&gt;&lt;img alt=&#34;Donate using Liberapay&#34; src=&#34;https://liberapay.com/assets/widgets/donate.svg&#34;&gt;&lt;/a&gt;&lt;/noscript&gt;
      &lt;/td&gt;
   &lt;/tr&gt;
&lt;/table&gt;
</description>
    </item>
    
    <item>
      <title>Today I Realized that to live reload my Lisp web app is straightforward and so convenient</title>
      <link>/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/</link>
      <pubDate>Tue, 12 May 2020 16:02:05 +0200</pubDate>
      
      <guid>/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/</guid>
      <description>&lt;p&gt;We all know that we can start a web server in the REPL and develop a
web app as interactively as any other app, we know how to &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html#remote-debugging&#34;&gt;connect to
a remote Lisp
image&lt;/a&gt;
by starting a Swank server and how to interact with it from our
favorite editor on our machine, we know we can build a self-contained
binary of the web app and simply run it, but one thing I had not
realized, despite being the basics, is that by starting the web app
with &lt;code&gt;sbcl --load app.lisp&lt;/code&gt;, we are dropped into the regular Lisp
REPL, with the web server running in its own thread (as in development
mode, but unlike with the binary), and that we can consequently interact with the running app.&lt;/p&gt;

&lt;p&gt;As a demonstration, you can clone &lt;a href=&#34;https://github.com/vindarel/lisp-web-live-reload-example&#34;&gt;this repository&lt;/a&gt; and run the example like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;* rlwrap sbcl --load run.lisp

This is SBCL 1.4.5.debian, an implementation of ANSI Common Lisp.
re information about SBCL is available at &amp;lt;http://www.sbcl.org/&amp;gt;.
[…]
; Loading &amp;quot;web-live-reload&amp;quot;
..................................................
Starting the web server on port 7890
Ready. You can access the application!
*
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it will load &lt;code&gt;project.asd&lt;/code&gt;, install 3 Quicklisp dependencies (you must
have Quicklisp installed), start Hunchentoot on port 7890, and drop us
into a REPL.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll get this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/lisp-web-live-reload-example/master/start.png&#34; style=&#34;max-width: 100%&#34;/&gt;&lt;/p&gt;

&lt;p&gt;The template prints the &lt;code&gt;*config*&lt;/code&gt; variable, which you can change in the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;* (in-package :web-live-reload)
* (setf *config*
    &#39;((:key &amp;quot;Name&amp;quot;
       :val &amp;quot;James&amp;quot;)
      (:key &amp;quot;phone&amp;quot;
       :val &amp;quot;0098 007&amp;quot;)
      (:key &amp;quot;secret language?&amp;quot;
       :val &amp;quot;Lisp&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;refresh, and voilà, your new config is live.&lt;/p&gt;

&lt;p&gt;For functions, it is just the same (redefine the function &lt;code&gt;fn&lt;/code&gt; that
returns a string, if you want to try).&lt;/p&gt;

&lt;p&gt;If a file changes (for example after a git pull), compile it with a
usual &lt;code&gt;load&lt;/code&gt;: &lt;code&gt;(load &amp;quot;src/web.lisp&amp;quot;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also reload all the app with &lt;code&gt;(ql:quickload :myproject)&lt;/code&gt;,
which will install the dependencies, without needing to restart the
running image.&lt;/p&gt;

&lt;p&gt;I was looking for a way to reload a user&amp;rsquo;s config and personal data
from a running website, and this has proved very practical. I have no
downtime, it is pure Lisp, it is the workflow I am used to. I am more
cautious on using this to recompile the whole app, even though I did
it without glitches so far. The thing to &lt;em&gt;not&lt;/em&gt; do is to change the
global state manually, aka to develop in production!&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s all, but that made my day.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Bonus points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;after a git pull, the (Djula) templates are automatically
updated. No operation is needed to see them live. (you can disable
this by pushing &lt;code&gt;:djula-prod&lt;/code&gt; into the features set)&lt;/li&gt;
&lt;li&gt;you&amp;rsquo;ll understand and appreciate the difference between
&lt;code&gt;defparameter&lt;/code&gt; and &lt;code&gt;defvar&lt;/code&gt;. Imagine you declare a variable with
&lt;code&gt;(defparameter *data* nil)&lt;/code&gt; and you populate it with some heavy
computation at the application startup. Now if you &lt;code&gt;load&lt;/code&gt; the file
this declaration is in, you&amp;rsquo;ll set the data back to &lt;code&gt;nil&lt;/code&gt;. If you
declare it with &lt;code&gt;defvar&lt;/code&gt;, you can live-re&lt;code&gt;load&lt;/code&gt; your app and the
data doesn&amp;rsquo;t go away. You can try both cases with the &lt;code&gt;*config*&lt;/code&gt;
variable.&lt;/li&gt;
&lt;li&gt;the app started a Swank server on port 4006, if you want to try on your VPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a href=&#34;https://www.patreon.com/bePatron?u=35783903&#34; data-patreon-widget-type=&#34;become-patron-button&#34;&gt;become a Patron!&lt;/a&gt;&lt;script async src=&#34;https://c6.patreon.com/becomePatronButton.bundle.js&#34;&gt;&lt;/script&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I Worked Remotely in Common Lisp. Here&#39;s My Incredible Story.</title>
      <link>/blog/i-worked-remotely-in-common-lisp-heres-my-incredible-story/</link>
      <pubDate>Tue, 12 May 2020 12:52:57 +0200</pubDate>
      
      <guid>/blog/i-worked-remotely-in-common-lisp-heres-my-incredible-story/</guid>
      <description>&lt;p&gt;Nearly one year ago, I received an email that asked me if I was
available to do remote Lisp work. It was the day before the end of a
contract and I had to tell my team if I wanted to continue or not. I
made a virtual offering to the Lisp god and I started the Lisp job.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Disclaimer: this post was written on &lt;a href=&#34;https://www.reddit.com/r/lispadvocates/comments/fopbgn/i_have_worked_in_common_lisp_remotely_heres_my/&#34;&gt;Lisp Advocates&amp;rsquo;
reddit&lt;/a&gt;. Lisp Advocates is a meme, but it&amp;rsquo;s sort of serious too.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;At this time I had been in Lisp for around two years, contributing a
couple simple libraries, writing a lot of documentation, blogging,
furnishing the reddits, and being enthusiastic and polite. This is
what actually gave me the job. I had tried to contribute to a busy CL
repository, but the PR was not good enough and that irritated the
maintainer, who answered abruptly. Nothing&amp;rsquo;s more outrageous than
receiving contributions right? But I answered with calm and
professionalism, and that got noticed by a repository watcher, who
decided he could work with me.&lt;/p&gt;

&lt;p&gt;That guy already had contacts and a client, and he formed a team
around him. Our work was to build a website that would receive many visitors,
that would have a client registration form and would
have a rather simple admin dashboard, for a team of half a dozen
people. The business already existed in the form of a buggy and slow
Wordpress site, so the expectations were clear. We were three, we
worked together on the same code (with one guy more on the design). I
worked on it in a two-months period, but not full time. I&amp;rsquo;ve had a
decent income paid straight and so I paid my rents for a few months
thanks to that experience.&lt;/p&gt;

&lt;p&gt;What Lisp was good for&lt;/p&gt;

&lt;p&gt;The application had no inherent difficulties. It had forms and an
admin backend. It was a website for a team of commercial people, as it
exists hundreds of thousands. And yeah, Common Lisp was suited for
that task. So we see there&amp;rsquo;s a good margin of progression, business
and remote work wise: those thousands of websites for commercial
people can very well be done in CL.&lt;/p&gt;

&lt;p&gt;Libraries, deployment and Lisp curse&lt;/p&gt;

&lt;p&gt;We picked the Caveman framework, the Mito ORM and the cl-markup
templating library, with some tests in FiveAM. There was a little bit
of JavaScript, less than a thousand lines. I find Caveman a bit
convoluted but it was clear and easy. I like Mito very much and wrote
material for it. I liked to play with the web server debugging options: usually I
received the stacktraces in the debugger in my editor, but I could
choose to display them on the browser (as I&amp;rsquo;m used with Django or
Flask). It is this time that I enjoyed so much being able to change
the faulty function, recompile it, choose the &amp;ldquo;try again&amp;rdquo; restart and
see the operation succeed. Now when I&amp;rsquo;m back on Python I feel the Lisp
curse. I&amp;rsquo;ll never be the same. I&amp;rsquo;ll never enjoy Python as much as
before. Sigh. Anyways, we deployed the app on DigitalOcean with Fast
CGI, as documented on Caveman&amp;rsquo;s README.&lt;/p&gt;

&lt;p&gt;The bug&lt;/p&gt;

&lt;p&gt;Our most difficult bug that made us loose millions was due to
&lt;code&gt;(string-downcase nil)&lt;/code&gt; to return &amp;ldquo;NIL&amp;rdquo;, the string, instead of
&lt;code&gt;nil&lt;/code&gt;. Now I use my &lt;a href=&#34;https://github.com/vindarel/cl-str/&#34;&gt;str&lt;/a&gt; library
for string manipulation purposes.&lt;/p&gt;

&lt;p&gt;All in all, being able to live-debug the software from the earth
proved invaluable.&lt;/p&gt;

&lt;p&gt;I got also hit by a config of mine that impacted Mito&amp;rsquo;s results. I had
set &lt;code&gt;*print-case*&lt;/code&gt; to &lt;code&gt;:downcase&lt;/code&gt; in my .sbclrc. I was asking Lisp to
DON&amp;rsquo;T SHOUT AT ME ALL DAY LONG, &amp;lsquo;cause I try to listen to music at the
same time. I fixed the Mito bug, but I don&amp;rsquo;t use this setting anymore.&lt;/p&gt;

&lt;p&gt;Voilà. This is my response to LispAdvocates&amp;rsquo; call: &lt;a href=&#34;https://www.reddit.com/r/lispadvocates/comments/ficdvx/tell_us_you_remote_success_story/&#34;&gt;https://www.reddit.com/r/lispadvocates/comments/ficdvx/tell_us_you_remote_success_story/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are of course lots of situations were CL is ready now to get the (remote) job done. There are people who do web dev for years in CL, but we don&amp;rsquo;t know their story.&lt;/p&gt;

&lt;p&gt;Share yours!&lt;/p&gt;

&lt;p&gt;ps: stay tuned, &amp;lsquo;cause I deployed another website in production.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Some comments and answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Apart from the programmer experience, were there any inherent advantages to using Common Lisp? (Speed I guess?)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;CL had no particular advantages, but no disadvantages either (and it
is my point!). As I said, it was a site with basic/easy/HTML&amp;amp;JS
requirements, so I believe no language would&amp;rsquo;ve had any particular
advantage. Speed was important, it was one of the main
requirements. The website felt responsive, the client was very happy
about it. For us, it was also easy and fast to deploy, which turned
important and impressed the client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do you thinK a more standardized framework (from other languages) could have saved you?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No, not with our requirements. Another framework&amp;amp;language would have
make us loose millions at the very beginning (still figuratively)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Custom Djula filters</title>
      <link>/blog/custom-djula-filter/</link>
      <pubDate>Wed, 08 Apr 2020 11:38:17 +0200</pubDate>
      
      <guid>/blog/custom-djula-filter/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://github.com/mmontone/djula/&#34;&gt;Djula&lt;/a&gt; is a Common Lisp port of
the Django templating language. It&amp;rsquo;s good, it&amp;rsquo;s proven (it&amp;rsquo;s one of
the most downloaded Quicklisp packages), it is easy to use and it has &lt;a href=&#34;http://mmontone.github.io/djula/doc/build/html/index.html&#34;&gt;good
documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It basically looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;    {% extends &amp;quot;base.html&amp;quot; %}
    {% block title %}Memberlist{% endblock %}
    {% block content %}
      &amp;lt;ul&amp;gt;
      {% for user in users %}
        &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;{{ user.url }}&amp;quot;&amp;gt;{{ user.username }}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      {% endfor %}
      &amp;lt;/ul&amp;gt;
    {% endblock %}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What was missing in the documentation was how to create custom
filters. Here&amp;rsquo;s how, and it&amp;rsquo;s very simple.&lt;/p&gt;

&lt;h2 id=&#34;def-filter&#34;&gt;def-filter&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;def-filter&lt;/code&gt; macro. Its general form is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(def-filter :myfilter-name (value arg)
  (body))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It always takes the variable&amp;rsquo;s value as argument, and it can have one
required or optional argument. For example, this is how those
built-in filters are defined:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(def-filter :capfirst (val)
  (string-capitalize (princ-to-string val)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is all there is to it. Once written, you can use it in your
templates. You can define a filter wherever you want and there is no
need to register it or to import it in your templates.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a filter with a required argument:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(def-filter :add (it n)
  (+ it (parse-integer n)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and with an optional one:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(def-filter :datetime (it &amp;amp;optional format)
  (let ((timestamp …))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you need to pass a second argument, make your filter return a
lambda function and chain it with the &lt;code&gt;with&lt;/code&gt; filter:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;    (def-filter :replace (it regex)
       (lambda (replace)
         (ppcre:regex-replace-all regex it replace)))

    (def-filter :with (it replace)
       (funcall it replace))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can write::&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{{ value | replace:foo | with:bar }}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note: we should most probably be able to define filters with two
arguments. There&amp;rsquo;s an open issue about that.&lt;/p&gt;

&lt;h2 id=&#34;error-handling&#34;&gt;Error handling&lt;/h2&gt;

&lt;p&gt;Errors are handled by the macro, but you can handle them and return a
&lt;code&gt;template-error&lt;/code&gt; condition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(def-filter :handle-error-filter (it)
   (handler-case
         (do-something)
     (condition (e)
       (template-error &amp;quot;There was an error executing this filter: ~A&amp;quot; e))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will be rendered on the browser with a nice stacktrace.&lt;/p&gt;

&lt;h2 id=&#34;final-words&#34;&gt;Final words&lt;/h2&gt;

&lt;p&gt;If you don&amp;rsquo;t know what template engine to use for your web project,
start with it. My only criticism is that accessing variables is not
totally flexible. The &lt;code&gt;{{ obj.val }}&lt;/code&gt; syntax already works to access
objects&amp;rsquo; slots, alists, plists, hash-tables and whatnot (it uses the
excellent
&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/&#34;&gt;Access&lt;/a&gt;
library), but it won&amp;rsquo;t work for some data (like structures), forcing
you to a bit of pre-processing before rendering the template. And you
can&amp;rsquo;t use much logic with template tags. However, this is by
design. Djula is a port of the Django templating engine after all.&lt;/p&gt;

&lt;p&gt;For more flexible templates and still write html (because, you know, we can copy-paste examples easily!), see &lt;a href=&#34;https://github.com/eudoxia0/eco&#34;&gt;Eco&lt;/a&gt;. See more templates engines in the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#html-generators-and-templates&#34;&gt;Awesome-cl list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Last-minute addition&lt;/strong&gt;: while I was writing this, Djula&amp;rsquo;s author released &lt;a href=&#34;https://github.com/mmontone/ten&#34;&gt;TEN, another templating engine&lt;/a&gt;, combining the best of Djula and Eco.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mmontone.github.io/djula/doc/build/html/filters.html#custom-filters&#34;&gt;https://mmontone.github.io/djula/doc/build/html/filters.html#custom-filters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>GUI Programming in Common Lisp, part 5/5: Nuklear</title>
      <link>/blog/gui-programming-in-common-lisp-part-5-of-5-nuklear/</link>
      <pubDate>Fri, 27 Mar 2020 13:19:45 +0100</pubDate>
      
      <guid>/blog/gui-programming-in-common-lisp-part-5-of-5-nuklear/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://github.com/Immediate-Mode-UI/Nuklear&#34;&gt;Nuklear&lt;/a&gt; is a small &lt;a href=&#34;https://en.wikipedia.org/wiki/Immediate_mode_GUI&#34;&gt;immediate-mode&lt;/a&gt; GUI toolkit:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Immediate-Mode-UI/Nuklear&#34;&gt;Nuklear&lt;/a&gt; is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;its Lisp binding is &lt;a href=&#34;https://github.com/borodust/bodge-nuklear&#34;&gt;Bodge-Nuklear&lt;/a&gt;, and its higher level companions &lt;a href=&#34;https://github.com/borodust/bodge-ui&#34;&gt;bodge-ui&lt;/a&gt; and &lt;a href=&#34;https://github.com/borodust/bodge-ui-window&#34;&gt;bodge-ui-window&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unlike traditional UI frameworks, Nuklear allows the developer to take
over the rendering loop or the input management. This might require
more setup, but it makes Nuklear particularly well suited for games,
or for applications where you want to create new controls.&lt;/p&gt;

&lt;p&gt;Previous posts of the serie:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-1-of-5-tk/&#34;&gt;part 1: Ltk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/&#34;&gt;part 2: Qt4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/&#34;&gt;part 3: Gtk+3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-4-of-5-iup/&#34;&gt;part 4: IUP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/gui.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/gui.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Framework written in&lt;/strong&gt;: ANSI C, single-header library.&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portability&lt;/strong&gt;: where C runs. Nuklear doesn&amp;rsquo;t contain
platform-specific code. No direct OS or window handling is done in
Nuklear. Instead &lt;em&gt;all input state has to be provided by platform
specific code&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Widgets choice&lt;/strong&gt;: small.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Graphical builder&lt;/strong&gt;: no.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other features&lt;/strong&gt;: fully skinnable and customisable.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings stability&lt;/strong&gt;: stable&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings activity&lt;/strong&gt;: active&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Licence&lt;/strong&gt;: MIT or Public Domain (unlicence).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Example applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/borodust/trivial-gamekit&#34;&gt;Trivial-gamekit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/thicksteadTHpp/Obvius/&#34;&gt;Obvius&lt;/a&gt; - a resurrected image processing library.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/borodust/notalone&#34;&gt;Notalone&lt;/a&gt; - an autumn 2017 Lisp Game Jam entry.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;List of widgets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Non-exhaustive list:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;buttons, progressbar, image selector, (collapsable) tree, list, grid, range, slider, color picker,
date-picker
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://vindarel.github.io/cl-cookbook/assets/gui/nuklear.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;getting-started&#34;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: as per the author&amp;rsquo;s words at the time of writing,
bodge-ui is in early stages of development and not ready for general
use yet. There are some quirks that need to be fixed, which might
require some changes in the API.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bodge-ui&lt;/code&gt; is not in Quicklisp but in its own Quicklisp distribution. Let&amp;rsquo;s install it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql-dist:install-dist &amp;quot;http://bodge.borodust.org/dist/org.borodust.bodge.txt&amp;quot; :replace t :prompt nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Uncomment and evaluate this line only if you want to enable the OpenGL 2
renderer:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; (cl:pushnew :bodge-gl2 cl:*features*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quickload &lt;code&gt;bodge-ui-window&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :bodge-ui-window)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can run the built-in example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :bodge-ui-window/examples)
(bodge-ui-window.example.basic:run)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let&amp;rsquo;s define a package to write a simple application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(cl:defpackage :bodge-ui-window-test
  (:use :cl :bodge-ui :bodge-host))
(in-package :bodge-ui-window-test)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defpanel (main-panel
            (:title &amp;quot;Hello Bodge UI&amp;quot;)
            (:origin 200 50)
            (:width 400) (:height 400)
            (:options :movable :resizable
                      :minimizable :scrollable
                      :closable))
  (label :text &amp;quot;Nested widgets:&amp;quot;)
  (horizontal-layout
   (radio-group
    (radio :label &amp;quot;Option 1&amp;quot;)
    (radio :label &amp;quot;Option 2&amp;quot; :activated t))
   (vertical-layout
    (check-box :label &amp;quot;Check 1&amp;quot; :width 100)
    (check-box :label &amp;quot;Check 2&amp;quot;))
   (vertical-layout
    (label :text &amp;quot;Awesomely&amp;quot; :align :left)
    (label :text &amp;quot;Stacked&amp;quot; :align :centered)
    (label :text &amp;quot;Labels&amp;quot; :align :right)))
  (label :text &amp;quot;Expand by width:&amp;quot;)
  (horizontal-layout
   (button :label &amp;quot;Dynamic&amp;quot;)
   (button :label &amp;quot;Min-Width&amp;quot; :width 80)
   (button :label &amp;quot;Fixed-Width&amp;quot; :expandable nil :width 100))
  )

(defun run ()
  (bodge-host:open-window (make-instance &#39;main-window)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and run it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(run)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://vindarel.github.io/cl-cookbook/assets/gui/nuklear-test.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;To react to events, use the following signals:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:on-click
:on-hover
:on-leave
:on-change
:on-mouse-press
:on-mouse-release
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;They take as argument a function with one argument, the panel. But
beware: they will be called on each rendering cycle when the widget is
on the given state, so potentially a lot of times.&lt;/p&gt;

&lt;h3 id=&#34;interactive-development&#34;&gt;Interactive development&lt;/h3&gt;

&lt;p&gt;If you ran the example in the REPL, you couldn&amp;rsquo;t see what&amp;rsquo;s cool. Put
the code in a lisp file and run it, so than you get the window. Now
you can change the panel widgets and the layout, and your changes will
be immediately applied while the application is running!&lt;/p&gt;

&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Have fun, don&amp;rsquo;t hesitate to share your experience and your apps… and contribute to the Cookbook!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GUI Programming in Common Lisp, part 4/5: IUP</title>
      <link>/blog/gui-programming-in-common-lisp-part-4-of-5-iup/</link>
      <pubDate>Fri, 27 Mar 2020 13:11:36 +0100</pubDate>
      
      <guid>/blog/gui-programming-in-common-lisp-part-4-of-5-iup/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;http://webserver2.tecgraf.puc-rio.br/iup/&#34;&gt;IUP&lt;/a&gt; is a cross-platform GUI toolkit actively developed
at the PUC university of Rio de Janeiro, Brazil. It uses &lt;strong&gt;native
controls&lt;/strong&gt;: the Windows API for Windows, Gtk3 for GNU/Linux. At the
time of writing, it has a Cocoa port in the works (as well as iOS,
Android and WASM ones). A particularity of IUP is its &lt;strong&gt;small API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Lisp bindings are &lt;a href=&#34;https://github.com/lispnik/iup/&#34;&gt;lispnik/iup&lt;/a&gt;. They are nicely
done in that they are automatically generated from the C sources. They
can follow new IUP versions with a minimal work and the required steps
are documented. All this gives us good guarantee over the bus
factor.&lt;/p&gt;

&lt;p&gt;IUP stands as a great solution in between Tk and Gtk or Qt.&lt;/p&gt;

&lt;p&gt;Previous posts of the serie:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-1-of-5-tk/&#34;&gt;part 1: Ltk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/&#34;&gt;part 2: Qt4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/&#34;&gt;part 3: Gtk+3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/gui.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/gui.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Framework written in&lt;/strong&gt;: C (official API also in Lua and LED)&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portability&lt;/strong&gt;: Windows and Linux, work started for
Cocoa, iOS, Android, WASM.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Widgets choice&lt;/strong&gt;: medium.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Graphical builder&lt;/strong&gt;: yes: &lt;a href=&#34;http://webserver2.tecgraf.puc-rio.br/iup/en/iupvisualled.html&#34;&gt;IupVisualLED&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other features&lt;/strong&gt;: OpenGL, Web browser (WebKitGTK on GNU/Linux), plotting, Scintilla text editor&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings documentation&lt;/strong&gt;: good examples and good readme, otherwise low.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings stability&lt;/strong&gt;: alpha (but fully generated and working nicely)&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings activity&lt;/strong&gt;: low&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Licence&lt;/strong&gt;: IUP and the bindings are MIT licenced.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;List of widgets&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Radio, Tabs, FlatTabs, ScrollBox, DetachBox,
Button, FlatButton, DropButton, Calendar, Canvas, Colorbar, ColorBrowser, DatePick, Dial, Gauge, Label, FlatLabel,
FlatSeparator, Link, List, FlatList, ProgressBar, Spin, Text, Toggle, Tree, Val,
listDialog, Alarm, Color, Message, Font, Scintilla, file-dialog…
Cells, Matrix, MatrixEx, MatrixList,
GLCanvas, Plot, MglPlot, OleControl, WebBrowser (WebKit/Gtk+)…
drag-and-drop
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- editor&#39;s note: found missing a list view with columns. --&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/lispnik/iup/master/docs/screenshots/sample-01.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;getting-started&#34;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;Please check the installation instructions upstream. You may need one
system dependency on GNU/Linux, and to modify an environment variable
on Windows.&lt;/p&gt;

&lt;p&gt;Finally, do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :iup)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We are not going to &lt;code&gt;:use&lt;/code&gt; IUP (it is a bad practice generally after all).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defpackage :test-iup
  (:use :cl))
(in-package :test-iup)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following snippet creates a dialog frame to display a text label.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello ()
  (iup:with-iup ()
    (let* ((label (iup:label :title (format nil &amp;quot;Hello, World!~%IUP ~A~%~A ~A&amp;quot;
                                            (iup:version)
                                            (lisp-implementation-type)
                                            (lisp-implementation-version))))
           (dialog (iup:dialog label :title &amp;quot;Hello, World!&amp;quot;)))
      (iup:show dialog)
      (iup:main-loop))))
(hello)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Important note for SBCL: we currently must trap division-by-zero
errors (see advancement on &lt;a href=&#34;https://github.com/lispnik/iup/issues/30&#34;&gt;this
issue&lt;/a&gt;). So, run snippets
like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun run-gui-function ()
  #-sbcl (gui-function)
  #+sbcl
  (sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (gui-function)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;How to run the main loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As with all the bindings seen so far, widgets are shown inside a
&lt;code&gt;with-iup&lt;/code&gt; macro, and with a call to &lt;code&gt;iup:main-loop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to create widgets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The constructor function is the name of the widget: &lt;code&gt;iup:label&lt;/code&gt;,
&lt;code&gt;iup:dialog&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to display a widget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Be sure to &amp;ldquo;show&amp;rdquo; it: &lt;code&gt;(iup:show dialog)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can group widgets on &lt;code&gt;frame&lt;/code&gt;s, and stack them vertically or
horizontally (with &lt;code&gt;vbox&lt;/code&gt; or &lt;code&gt;hbox&lt;/code&gt;, see the example below).&lt;/p&gt;

&lt;p&gt;To allow a widget to be expanded on window resize, use &lt;code&gt;:expand
:yes&lt;/code&gt; (or &lt;code&gt;:horizontal&lt;/code&gt; and &lt;code&gt;:vertical&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Use also the &lt;code&gt;:alignement&lt;/code&gt; properties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to get and set a widget&amp;rsquo;s attributes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;(iup:attribute widget attribute)&lt;/code&gt; to get the attribute&amp;rsquo;s value,
and use &lt;code&gt;setf&lt;/code&gt; on it to set it.&lt;/p&gt;

&lt;h3 id=&#34;reacting-to-events&#34;&gt;Reacting to events&lt;/h3&gt;

&lt;p&gt;Most widgets take an &lt;code&gt;:action&lt;/code&gt; parameter that takes a lambda function
with one parameter (the handle).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(iup:button :title &amp;quot;Test &amp;amp;1&amp;quot;
            :expand :yes
            :tip &amp;quot;Callback inline at control creation&amp;quot;
            :action (lambda (handle)
                      (iup:message &amp;quot;title&amp;quot; &amp;quot;button1&#39;s action callback&amp;quot;)
                      iup:+default+))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Below we create a label and put a button below it. We display a
message dialog when we click on the button.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun click-button ()
  (iup:with-iup ()
    (let* ((label (iup:label :title (format nil &amp;quot;Hello, World!~%IUP ~A~%~A ~A&amp;quot;
                                            (iup:version)
                                            (lisp-implementation-type)
                                            (lisp-implementation-version))))
           (button (iup:button :title &amp;quot;Click me&amp;quot;
                               :expand :yes
                               :tip &amp;quot;yes, click me&amp;quot;
                               :action (lambda (handle)
                                         (declare (ignorable handle))
                                         (iup:message &amp;quot;title&amp;quot; &amp;quot;button clicked&amp;quot;)
                                         iup:+default+)))
           (vbox
            (iup:vbox (list label button)
                      :gap &amp;quot;10&amp;quot;
                      :margin &amp;quot;10x10&amp;quot;
                      :alignment :acenter))
           (dialog (iup:dialog vbox :title &amp;quot;Hello, World!&amp;quot;)))
      (iup:show dialog)
      (iup:main-loop))))

#+sbcl
(sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (click-button))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;rsquo;s a similar example to make a counter of clicks.  We use a label
and its title to hold the count. The title is an integer.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun counter ()
  (iup:with-iup ()
    (let* ((counter (iup:label :title 0))
           (label (iup:label :title (format nil &amp;quot;The button was clicked ~a time(s).&amp;quot;
                                            (iup:attribute counter :title))))
           (button (iup:button :title &amp;quot;Click me&amp;quot;
                               :expand :yes
                               :tip &amp;quot;yes, click me&amp;quot;
                               :action (lambda (handle)
                                         (declare (ignorable handle))
                                         (setf (iup:attribute counter :title)
                                               (1+ (iup:attribute counter :title &#39;number)))
                                         (setf (iup:attribute label :title)
                                               (format nil &amp;quot;The button was clicked ~a times.&amp;quot;
                                                       (iup:attribute counter :title)))
                                         iup:+default+)))
           (vbox
            (iup:vbox (list label button)
                      :gap &amp;quot;10&amp;quot;
                      :margin &amp;quot;10x10&amp;quot;
                      :alignment :acenter))
           (dialog (iup:dialog vbox :title &amp;quot;Counter&amp;quot;)))
      (iup:show dialog)
      (iup:main-loop))))

(defun run-counter ()
  #-sbcl
  (counter)
  #+sbcl
  (sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (counter)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;list-widget-example&#34;&gt;List widget example&lt;/h3&gt;

&lt;p&gt;Below we create three list widgets with simple and multiple selection, we
set their default value (the pre-selected row) and we place them
horizontally side by side.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun list-test ()
  (iup:with-iup ()
    (let*  ((list-1 (iup:list :tip &amp;quot;List 1&amp;quot;  ;; tooltip
                              ;; multiple selection
                              :multiple :yes
                              :expand :yes))
            (list-2 (iup:list :value 2   ;; default index of the selected row
                              :tip &amp;quot;List 2&amp;quot; :expand :yes))
            (list-3 (iup:list :value 9 :tip &amp;quot;List 3&amp;quot; :expand :yes))
            (frame (iup:frame
                    (iup:hbox
                     (progn
                       ;; populate the lists: display integers.
                       (loop for i from 1 upto 10
                          do (setf (iup:attribute list-1 i)
                                   (format nil &amp;quot;~A&amp;quot; i))
                          do (setf (iup:attribute list-2 i)
                                   (format nil &amp;quot;~A&amp;quot; (+ i 10)))
                          do (setf (iup:attribute list-3 i)
                                   (format nil &amp;quot;~A&amp;quot; (+ i 50))))
                       ;; hbox wants a list of widgets.
                       (list list-1 list-2 list-3)))
                    :title &amp;quot;IUP List&amp;quot;))
            (dialog (iup:dialog frame :menu &amp;quot;menu&amp;quot; :title &amp;quot;List example&amp;quot;)))

      (iup:map dialog)
      (iup:show dialog)
      (iup:main-loop))))

(defun run-list-test ()
  #-sbcl (hello)
  #+sbcl
  (sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (list-test)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next is a different toolkit very well suited for games and that enables fully interactive development: Nuklear.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GUI Programming in Common Lisp, part 3/5: Gtk3</title>
      <link>/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/</link>
      <pubDate>Fri, 27 Mar 2020 13:05:22 +0100</pubDate>
      
      <guid>/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/</guid>
      <description>

&lt;p&gt;We continue our tour of GUI toolkits for CL with Gtk+3 and cl-cffi-gtk.&lt;/p&gt;

&lt;p&gt;The previosu posts are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-1-of-5-tk/&#34;&gt;part 1: Ltk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/&#34;&gt;part 2: Qt4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/gui.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/gui.html&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;gtk-3-cl-cffi-gtk&#34;&gt;Gtk+3 (cl-cffi-gtk)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://www.gtk.org/&#34;&gt;Gtk+3&lt;/a&gt; is the primary library used to build &lt;a href=&#34;https://www.gnome.org/&#34;&gt;GNOME&lt;/a&gt;
applications. Its (currently most advanced) lisp bindings is
&lt;a href=&#34;https://github.com/Ferada/cl-cffi-gtk/&#34;&gt;cl-cffi-gtk&lt;/a&gt;. While primarily created for GNU/Linux, Gtk
works fine under macOS and can now also be used on Windows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Framework written in&lt;/strong&gt;: C&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portability&lt;/strong&gt;: GNU/Linux and macOS, also Windows.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Widgets choice&lt;/strong&gt;: large.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Graphical builder&lt;/strong&gt;: yes: Glade.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other features&lt;/strong&gt;: web browser (WebKitGTK)&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings documentation&lt;/strong&gt;: very good: &lt;a href=&#34;http://www.crategus.com/books/cl-gtk/gtk-tutorial.html&#34;&gt;http://www.crategus.com/books/cl-gtk/gtk-tutorial.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings stability&lt;/strong&gt;: stable&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings activity&lt;/strong&gt;: low activity, active development.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Licence&lt;/strong&gt;: LGPL&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Example applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an &lt;a href=&#34;https://github.com/ralph-schleicher/atmosphere-calculator&#34;&gt;Atmosphere Calculator&lt;/a&gt;, built with Glade.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;getting-started&#34;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;The
&lt;a href=&#34;http://www.crategus.com/books/cl-gtk/gtk-tutorial.html&#34;&gt;documentation&lt;/a&gt;
is exceptionally good, including for beginners.&lt;/p&gt;

&lt;p&gt;The library to quickload is &lt;code&gt;cl-cffi-gtk&lt;/code&gt;. It is made of numerous
ones, that we have to &lt;code&gt;:use&lt;/code&gt; for our package.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :cl-cffi-gtk)

(defpackage :gtk-tutorial
  (:use :gtk :gdk :gdk-pixbuf :gobject
   :glib :gio :pango :cairo :common-lisp))

(in-package :gtk-tutorial)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;How to run the main loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As with the other libraries, everything happens inside the main loop
wrapper, here &lt;code&gt;with-main-loop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to create a window&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(make-instance &#39;gtk-window :type :toplevel :title &amp;quot;hello&amp;quot; ...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to create a widget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All widgets have a corresponding class. We can create them with
&lt;code&gt;make-instance &#39;widget-class&lt;/code&gt;, but we preferably use the constructors.&lt;/p&gt;

&lt;p&gt;The constructors end with (or contain) &amp;ldquo;new&amp;rdquo;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(gtk-label-new)
(gtk-button-new-with-label &amp;quot;Label&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;How to create a layout&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((box (make-instance &#39;gtk-box :orientation :horizontal :spacing 6))) ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then pack a widget onto the box:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(gtk-box-pack-start box mybutton-1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and add the box to the window:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(gtk-container-add window box)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and display them all:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(gtk-widget-show-all window)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;reacting-to-events&#34;&gt;Reacting to events&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;g-signal-connect&lt;/code&gt; + the concerned widget + the event name (as a
string) + a lambda, that takes the widget as argument:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(g-signal-connect window &amp;quot;destroy&amp;quot;
  (lambda (widget)
    (declare (ignore widget))
    (leave-gtk-main)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or again:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(g-signal-connect button &amp;quot;clicked&amp;quot;
  (lambda (widget)
    (declare (ignore widget))
    (format t &amp;quot;Button was pressed.~%&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;full-example&#34;&gt;Full example&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello-world ()
  ;; in the docs, this is example-upgraded-hello-world-2.
  (within-main-loop
    (let ((window (make-instance &#39;gtk-window
                                 :type :toplevel
                                 :title &amp;quot;Hello Buttons&amp;quot;
                                 :default-width 250
                                 :default-height 75
                                 :border-width 12))
          (box (make-instance &#39;gtk-box
                              :orientation :horizontal
                              :spacing 6)))
      (g-signal-connect window &amp;quot;destroy&amp;quot;
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      (let ((button (gtk-button-new-with-label &amp;quot;Button 1&amp;quot;)))
        (g-signal-connect button &amp;quot;clicked&amp;quot;
                          (lambda (widget)
                            (declare (ignore widget))
                            (format t &amp;quot;Button 1 was pressed.~%&amp;quot;)))
        (gtk-box-pack-start box button))
      (let ((button (gtk-button-new-with-label &amp;quot;Button 2&amp;quot;)))
        (g-signal-connect button &amp;quot;clicked&amp;quot;
                          (lambda (widget)
                            (declare (ignore widget))
                            (format t &amp;quot;Button 2 was pressed.~%&amp;quot;)))
        (gtk-box-pack-start box button))
      (gtk-container-add window box)
      (gtk-widget-show-all window))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://vindarel.github.io/cl-cookbook/assets/gui/gtk3-hello-buttons.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Next is IUP, a not very famous but really great toolkit!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GUI Programming in Common Lisp, part 2/5: Qt4 with Qtools</title>
      <link>/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/</link>
      <pubDate>Fri, 27 Mar 2020 12:42:59 +0100</pubDate>
      
      <guid>/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/</guid>
      <description>

&lt;p&gt;Here&amp;rsquo;s the second part of our exploration of GUI toolkits for Common Lisp.&lt;/p&gt;

&lt;p&gt;The first part and introduction is accessible here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/gui-programming-in-common-lisp-part-1-of-5-tk/&#34;&gt;part 1: Ltk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/gui.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/gui.html&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;qt4-qtools&#34;&gt;Qt4 (Qtools)&lt;/h2&gt;

&lt;p&gt;Do we need to present Qt and &lt;a href=&#34;https://doc.qt.io/archives/qt-4.8/index.html&#34;&gt;Qt4&lt;/a&gt;? Qt is huge and contains
everything and the kitchen sink. Qt not only provides UI widgets, but
numerous other layers (networking, D-BUS…).&lt;/p&gt;

&lt;p&gt;Qt is free for open-source software, however you&amp;rsquo;ll want to check the
conditions to ship proprietary ones.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/Shinmera/qtools&#34;&gt;Qtools&lt;/a&gt; bindings target Qt4. The Qt5 Lisp bindings are
yet to be created.&lt;/p&gt;

&lt;!-- possible future: gobject-introspection --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Framework written in&lt;/strong&gt;: C++&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Framework Portability&lt;/strong&gt;: multi-platform, Android, embedded systems, WASM.&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings Portability&lt;/strong&gt;: Qtools runs on x86 desktop platforms on Windows, macOS and GNU/Linux.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Widgets choice&lt;/strong&gt;: large.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Graphical builder&lt;/strong&gt;: yes.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other features&lt;/strong&gt;: Web browser, a lot more.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings documentation&lt;/strong&gt;: lengthy explanations, a few examples. Prior Qt knowledge is required.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings stability&lt;/strong&gt;: stable&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings activity&lt;/strong&gt;: active&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Qt Licence&lt;/strong&gt;: both commercial and open source licences.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Example applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shinmera/qtools/tree/master/examples&#34;&gt;https://github.com/Shinmera/qtools/tree/master/examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shirakumo/lionchat&#34;&gt;https://github.com/Shirakumo/lionchat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/shinmera/halftone&#34;&gt;https://github.com/shinmera/halftone&lt;/a&gt; - a simple image viewer&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;getting-started&#34;&gt;Getting started&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &#39;(:qtools :qtcore :qtgui))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defpackage #:qtools-test
  (:use #:cl+qt)
  (:export #:main))
(in-package :qtools-test)
(in-readtable :qtools)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create our main widget that will contain the rest:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-widget main-window (QWidget)
  ())
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create an input field and a button inside this main widget:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-subwidget (main-window name) (q+:make-qlineedit main-window)
  (setf (q+:placeholder-text name) &amp;quot;Your name please.&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-subwidget (main-window go-button) (q+:make-qpushbutton &amp;quot;Go!&amp;quot; main-window))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We stack them horizontally:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-subwidget (main-window layout) (q+:make-qhboxlayout main-window)
  (q+:add-widget layout name)
  (q+:add-widget layout go-button))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we show them:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-main-window
  (window &#39;main-window))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://vindarel.github.io/cl-cookbook/assets/gui/qtools-intro.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s cool, but we don&amp;rsquo;t react to the click event yet.&lt;/p&gt;

&lt;h3 id=&#34;reacting-to-events&#34;&gt;Reacting to events&lt;/h3&gt;

&lt;p&gt;Reacting to events in Qt happens through signals and slots. &lt;strong&gt;Slots&lt;/strong&gt; are
functions that receive or &amp;ldquo;connect to&amp;rdquo; signals, and &lt;strong&gt;signals&lt;/strong&gt; are event carriers.&lt;/p&gt;

&lt;p&gt;Widgets already send their own signals: for example, a button sends a
&amp;ldquo;pressed&amp;rdquo; event. So, most of the time, we only need to connect to them.&lt;/p&gt;

&lt;p&gt;However, had we extra needs, we can create our own set of signals.&lt;/p&gt;

&lt;h4 id=&#34;built-in-events&#34;&gt;Built-in events&lt;/h4&gt;

&lt;p&gt;We want to connect our &lt;code&gt;go-button&lt;/code&gt; to the &lt;code&gt;pressed&lt;/code&gt; and
&lt;code&gt;return-pressed&lt;/code&gt; events and display a message box.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we need to do this inside a &lt;code&gt;define-slot&lt;/code&gt; function,&lt;/li&gt;
&lt;li&gt;where we establish the connection to those events,&lt;/li&gt;
&lt;li&gt;and where we create the message box. We grab the text of the &lt;code&gt;name&lt;/code&gt;
input field with &lt;code&gt;(q+:text name)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-slot (main-window go-button) ()
  (declare (connected go-button (pressed)))
  (declare (connected name (return-pressed)))
  (q+:qmessagebox-information main-window
                              &amp;quot;Greetings&amp;quot;  ;; title
                              (format NIL &amp;quot;Good day to you, ~a!&amp;quot; (q+:text name))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And voilà. Run it with&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-main-window (window &#39;main-window))
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;custom-events&#34;&gt;Custom events&lt;/h4&gt;

&lt;p&gt;We&amp;rsquo;ll implement the same functionality as above, but for demonstration
purposes we&amp;rsquo;ll create our own signal named &lt;code&gt;name-set&lt;/code&gt; to throw when
the button is clicked.&lt;/p&gt;

&lt;p&gt;We start by defining the signal, which happens inside the
&lt;code&gt;main-window&lt;/code&gt;, and which is of type &lt;code&gt;string&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-signal (main-window name-set) (string))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create a &lt;strong&gt;first slot&lt;/strong&gt; to make our button react to the &lt;code&gt;pressed&lt;/code&gt;
and &lt;code&gt;return-pressed&lt;/code&gt; events. But instead of creating the message box
here, as above, we send the &lt;code&gt;name-set&lt;/code&gt; signal, with the value of our
input field..&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-slot (main-window go-button) ()
  (declare (connected go-button (pressed)))
  (declare (connected name (return-pressed)))
  (signal! main-window (name-set string) (q+:text name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, nobody reacts to &lt;code&gt;name-set&lt;/code&gt;. We create a &lt;strong&gt;second slot&lt;/strong&gt; that
connects to it, and displays our message. Here again, we precise the
parameter type.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-slot (main-window name-set) ((new-name string))
  (declare (connected main-window (name-set string)))
  (q+:qmessagebox-information main-window &amp;quot;Greetings&amp;quot; (format NIL &amp;quot;Good day to you, ~a!&amp;quot; new-name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and run it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-main-window (window &#39;main-window))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;building-and-deployment&#34;&gt;Building and deployment&lt;/h3&gt;

&lt;p&gt;It is possible to build a binary and bundle it together with all the
necessary shared libraries.&lt;/p&gt;

&lt;p&gt;Please read &lt;a href=&#34;https://github.com/Shinmera/qtools#deployment&#34;&gt;https://github.com/Shinmera/qtools#deployment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You might also like &lt;a href=&#34;https://github.com/phoe-trash/furcadia-post-splitter/blob/master/.travis.yml&#34;&gt;this Travis CI script&lt;/a&gt; to build a self-contained binary for the three OSes.&lt;/p&gt;

&lt;p&gt;Next, we&amp;rsquo;ll have a look at Gtk+3.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GUI Programming in Common Lisp, part 1/5: Tk</title>
      <link>/blog/gui-programming-in-common-lisp-part-1-of-5-tk/</link>
      <pubDate>Fri, 27 Mar 2020 12:20:36 +0100</pubDate>
      
      <guid>/blog/gui-programming-in-common-lisp-part-1-of-5-tk/</guid>
      <description>

&lt;p&gt;Lisp has a long and rich history and so does the development of
Graphical User Interfaces in Lisp. In fact, the first GUI builder was
written in Lisp (and sold to Apple. It is now Interface Builder).&lt;/p&gt;

&lt;p&gt;Lisp is also famous and unrivaled for its interactive development
capabilities, a feature even more worth having to develop GUI
applications. Can you imagine compiling one function and seeing your
GUI update instantly? We can do this with many GUI frameworks today,
even though the details differ from one to another.&lt;/p&gt;

&lt;p&gt;Finally, a key part in building software is how to build it and ship
it to users. Here also, we can build self-contained binaries, for
the three main operating systems, that users can run with a double
click.&lt;/p&gt;

&lt;p&gt;We aim here to give you the relevant information to help you choose
the right GUI framework and to put you on tracks. Don&amp;rsquo;t hesitate to
&lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/issues/&#34;&gt;contribute&lt;/a&gt;, to
send more examples and to furnish the upstream documentations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/gui.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/gui.html&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;In this article series, we&amp;rsquo;ll present the following GUI toolkits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tcl.tk&#34;&gt;Tk&lt;/a&gt; with &lt;a href=&#34;http://www.peter-herth.de/ltk/ltkdoc/&#34;&gt;Ltk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://doc.qt.io/archives/qt-4.8/index.html&#34;&gt;Qt4&lt;/a&gt; with &lt;a href=&#34;https://github.com/Shinmera/qtools&#34;&gt;Qtools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://webserver2.tecgraf.puc-rio.br/iup/&#34;&gt;IUP&lt;/a&gt; with &lt;a href=&#34;https://github.com/lispnik/iup/&#34;&gt;lispnik/iup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gtk.org/&#34;&gt;Gtk3&lt;/a&gt; with &lt;a href=&#34;https://github.com/Ferada/cl-cffi-gtk/&#34;&gt;cl-cffi-gtk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Immediate-Mode-UI/Nuklear&#34;&gt;Nuklear&lt;/a&gt; with &lt;a href=&#34;https://github.com/borodust/bodge-nuklear&#34;&gt;Bodge-Nuklear&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, you might want to have a look to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;a href=&#34;http://www.lispworks.com/products/capi.html&#34;&gt;CAPI&lt;/a&gt; toolkit (Common Application Programming Interface),
which is proprietary and made by LispWorks. It is a complete and cross-platform
toolkit (Windows, Gtk+, Cocoa), very praised by its users. LispWorks
also has &lt;a href=&#34;http://www.lispworks.com/products/lw4mr.html&#34;&gt;iOS and Android
runtimes&lt;/a&gt;. Example
software built with CAPI include &lt;a href=&#34;https://opusmodus.com/&#34;&gt;Opusmodus&lt;/a&gt;
or again &lt;a href=&#34;https://scorecloud.com/&#34;&gt;ScoreCloud&lt;/a&gt;. It is possible to
try it with the LispWorks free demo.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plkrueger/CocoaInterface/&#34;&gt;CocoaInterface&lt;/a&gt;, a
Cocoa interface for Clozure Common Lisp. Build Cocoa user interface
windows dynamically using Lisp code and bypass the typical Xcode
processes.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/mcclim/&#34;&gt;McCLIM&lt;/a&gt;, a toolkit in 100% Common Lisp.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shirakumo/alloy&#34;&gt;Alloy&lt;/a&gt;, another very new toolkit in 100% Common Lisp, used for example in the &lt;a href=&#34;https://github.com/shinmera/kandria&#34;&gt;Kandria&lt;/a&gt; game.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://notabug.org/cage/nodgui&#34;&gt;nodgui&lt;/a&gt;, a fork of Ltk, with syntax sugar and additional widgets.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/eql&#34;&gt;eql, eql5, eql5-android&lt;/a&gt;, embedded Qt4 and Qt5 Lisp, embedded in ECL, embeddable in Qt. Port of EQL5 to the Android platform.&lt;/li&gt;
&lt;li&gt;this &lt;a href=&#34;https://github.com/defunkydrummer/abcl-jazz&#34;&gt;demo using Java Swing from ABCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and, last but not least, &lt;a href=&#34;http://ceramic.github.io/&#34;&gt;Ceramic&lt;/a&gt;, to ship a cross-platform web app with Electron.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;as well as the other ones listed on &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#gui&#34;&gt;awesome-cl#gui&lt;/a&gt; and &lt;a href=&#34;https://www.cliki.net/GUI&#34;&gt;Cliki&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;tk-ltk&#34;&gt;Tk (Ltk)&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://www.tcl.tk&#34;&gt;Tk&lt;/a&gt; (or Tcl/Tk, where Tcl is the programming language) has the
infamous reputation of having an outdated look. This is not (so) true
anymore since its version 8 of 1997 (!). It is probably better than
you think:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://vindarel.github.io/cl-cookbook/assets/gui/ltk-on-macos.png&#34; alt=&#34;Ltk looks ok now&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Tk doesn&amp;rsquo;t have a great choice of widgets, but it has a useful canvas,
and it has a couple of unique features: we can develop a graphical
interface &lt;strong&gt;fully interactively&lt;/strong&gt; and we can run the GUI &lt;strong&gt;remotely&lt;/strong&gt;
from the core app.&lt;/p&gt;

&lt;p&gt;So, Tk isn&amp;rsquo;t fancy, but it is an used and proven GUI toolkit (and
programming language) still used in the industry. It can be a great
choice to quickly create simple GUIs, to leverage its ease of deployment, or
when stability is required.&lt;/p&gt;

&lt;p&gt;The Lisp binding is &lt;a href=&#34;http://www.peter-herth.de/ltk/ltkdoc/&#34;&gt;Ltk&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Written in&lt;/strong&gt;: Tcl&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portability&lt;/strong&gt;: cross-platform (Windows, macOS, Linux).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Widgets&lt;/strong&gt;: this is not the fort of Tk. It has a &lt;strong&gt;small set&lt;/strong&gt; of
default widgets, and misses important ones, for example a calendar. We
can find some in extensions (such as in &lt;strong&gt;Nodgui&lt;/strong&gt;), but they don&amp;rsquo;t
feel native, at all.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interactive development&lt;/strong&gt;: very much.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Graphical builder&lt;/strong&gt;: no&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;remote execution&lt;/strong&gt;: the connection between Lisp and Tcl/Tk is
done via a stream. It is thus possible to run the Lisp program on
one computer, and to display the GUI on another one. The only
thing required on the client computer is tcl/tk installed and the
remote.tcl script. See &lt;a href=&#34;http://www.peter-herth.de/ltk/ltkdoc/node46.html&#34;&gt;Ltk-remote&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings documentation&lt;/strong&gt;: short but complete. Nodgui too.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings stability&lt;/strong&gt;: very stable&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bindings activity&lt;/strong&gt;: low to non-existent.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Licence&lt;/strong&gt;: Tcl/Tk is BSD-style, Ltk is LGPL.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Example applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://notabug.org/cage/fulci/&#34;&gt;Fulci&lt;/a&gt; - a program to organize your movie collections.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mijohnson99/ltk-small-games&#34;&gt;Ltk small games&lt;/a&gt; - snake and tic-tac-toe.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-torrents&#34;&gt;cl-torrents&lt;/a&gt; - searching torrents on popular trackers. CLI, readline and a simple Tk GUI.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;List of widgets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(please don&amp;rsquo;t suppose the list exhaustive)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Button Canvas Check-button Entry Frame Label Labelframe Listbox
Menu Menubutton Message
Paned-window
Radio-button Scale
Scrollbar Spinbox Text
Toplevel Widget Canvas

Ltk-megawidgets:
    progress
    history-entry
    menu-entry
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nodgui adds:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;treelist tooltip searchable-listbox date-picker calendar autocomplete-listbox
password-entry progress-bar-star notify-window
dot-plot bar-chart equalizer-bar
swap-list
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;getting-started&#34;&gt;Getting started&lt;/h1&gt;

&lt;p&gt;Ltk is quick and easy to grasp.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :ltk)
(in-package :ltk-user)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;How to create widgets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All widgets are created with a regular &lt;code&gt;make-instance&lt;/code&gt; and the widget name:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;button)
(make-instance &#39;treeview)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This makes Ltk explorable with the default symbol completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to start the main loop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As with most bindings, the GUI-related code must be started inside a macro that
handles the main loop, here &lt;code&gt;with-ltk&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-ltk ()
  (let ((frame (make-instance &#39;frame)))
    …))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;How to display widgets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After we created some widgets, we must place them on the layout. There
are a few Tk systems for that, but the most recent one and the one we
should start with is the &lt;code&gt;grid&lt;/code&gt;. &lt;code&gt;grid&lt;/code&gt; is a function that takes as
arguments the widget, its column, its row, and a few optional
parameters.&lt;/p&gt;

&lt;p&gt;As with any Lisp code in a regular environment, the functions&amp;rsquo;
signatures are indicated by the editor. It makes Ltk explorable.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s how to display a button:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-ltk ()
  (let ((button (make-instance &#39;button :text &amp;quot;hello&amp;quot;)))
    (grid button 0 0)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s all there is to it.&lt;/p&gt;

&lt;h3 id=&#34;reacting-to-events&#34;&gt;Reacting to events&lt;/h3&gt;

&lt;p&gt;Many widgets have a &lt;code&gt;:command&lt;/code&gt; argument that accept a lambda which is
executed when the widget&amp;rsquo;s event is started. In the case of a button,
that will be on a click:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;button
  :text &amp;quot;Hello&amp;quot;
  :command (lambda ()
             (format t &amp;quot;clicked&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;interactive-development&#34;&gt;Interactive development&lt;/h3&gt;

&lt;p&gt;When we start the Tk process in the background with &lt;code&gt;(start-wish)&lt;/code&gt;, we
can create widgets and place them on the grid interactively.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&#34;http://www.peter-herth.de/ltk/ltkdoc/node8.html&#34;&gt;the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once we&amp;rsquo;re done, we can &lt;code&gt;(exit-wish)&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;nodgui&#34;&gt;Nodgui&lt;/h3&gt;

&lt;p&gt;To try the Nodgui demo, do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :nodgui)
(nodgui.demo:demo)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we&amp;rsquo;ll have a look at a very different beast, Qt4, with Qtools.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Literate Programming in Lisp With Erudite</title>
      <link>/blog/literate-programming-in-lisp-with-erudite/</link>
      <pubDate>Sat, 21 Mar 2020 11:01:57 +0100</pubDate>
      
      <guid>/blog/literate-programming-in-lisp-with-erudite/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://github.com/mmontone/erudite/&#34;&gt;Erudite&lt;/a&gt; is a Common Lisp library to write literate programs.
The latest release (march, 2020) brings cool new features, amongst which the
ability to capture and print code output.&lt;/p&gt;

&lt;p&gt;This page was created with Erudite. You can follow along with its
source &lt;a href=&#34;/blog/literate-erudite.lisp&#34;&gt;here&lt;/a&gt;. Blogging about a programming language in the language itself is
pretty awesome and convenient (no more copy-pasting of code snippets
and manual adjustements of the indentation, yay!). It brings us closer
to an interactive notebook, even if it isn&amp;rsquo;t the first goal.&lt;/p&gt;

&lt;h1 id=&#34;basic-usage&#34;&gt;Basic usage&lt;/h1&gt;

&lt;p&gt;You write a lisp program, as usual. There is no extra step to produce the program sources,
since we are inside the sources. This is different than the Org-mode approach for example.&lt;/p&gt;

&lt;p&gt;The comments will be the documentation. Comments inside a function are
also extracted and cut the function in two.&lt;/p&gt;

&lt;p&gt;Erudite can export to Latex, RestructuredText, Markdown, HTML… and
actually to and from any format by using a &amp;ldquo;pass-through&amp;rdquo; directive.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
Top level comments are shown like this. Here&amp;rsquo;s code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun fibonacci (n &amp;amp;aux (f0 0) (f1 1))
  &amp;quot;docstring&amp;quot;
  (case n
    (0 f0)
    (1 f1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this is an inline comment (there might be settings to control how it is rendered)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;    (t (loop for n from 2 to n
          for a = f0 then b and b = f1 then result
          for result = (+ a b)
          finally (return result)))))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Erudite defines directives to play with the output, such as &lt;code&gt;ignore&lt;/code&gt; and &lt;code&gt;eval&lt;/code&gt;. Note that directives start with a &lt;code&gt;@&lt;/code&gt; sign, which I cannot use here.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;ignore&lt;/code&gt;, we can write lisp code but hide it from the output. And with &lt;code&gt;eval&lt;/code&gt;, Erudite connects to a Swank server, captures and prints the output.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s also the handy &lt;code&gt;code&lt;/code&gt;, to write a snippet inside comments (so it is not part of
the Lisp source) and make it appear in the generated document.&lt;/p&gt;

&lt;p&gt;For the text markup, we can use Erudite&amp;rsquo;s
syntax (&amp;ldquo;link&amp;rdquo;, &amp;ldquo;section&amp;rdquo;, &amp;ldquo;subsection&amp;rdquo;, &amp;ldquo;emph&amp;rdquo;…), or the markup of
the output file format.&lt;/p&gt;

&lt;h1 id=&#34;evaluating-code&#34;&gt;Evaluating code&lt;/h1&gt;

&lt;p&gt;With the latest Erudite, we can evaluate code. Note that it&amp;rsquo;s a work
in progress.&lt;/p&gt;

&lt;p&gt;The code snippet must be inside the comments too.&lt;/p&gt;

&lt;p&gt;Here I call Fibonacci defined above: Fibonacci of 10 is…
&lt;br&gt;
55
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;You might need to create a Swank server first with&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(swank:create-server :dont-close t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and tell Erudite its port if it isn&amp;rsquo;t 4005.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(setf erudite::*swank-port* 4005)
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;rendering-the-document&#34;&gt;Rendering the document&lt;/h1&gt;

&lt;p&gt;Call Erudite like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(erudite:erudite #p&amp;quot;literal.md&amp;quot; &amp;quot;literal-erudite.lisp&amp;quot; :output-type :markdown)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also use a binary from the shell.&lt;/p&gt;

&lt;h1 id=&#34;live-rendering&#34;&gt;Live rendering&lt;/h1&gt;

&lt;p&gt;I don&amp;rsquo;t want to re-run this command everytime I want to see the generated document.
I use this snippet to automatically export my document when I save the Lisp source:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;
(ql:quickload :cl-inotify)

(bt:make-thread
 (lambda ()
   (cl-inotify:with-inotify (inotify t (&amp;quot;literal-erudite.lisp&amp;quot; :close-write))
     (cl-inotify:do-events (event inotify :blocking-p t)
       (format t &amp;quot;~a~&amp;amp;&amp;quot; event)
       (erudite:erudite #p&amp;quot;literal.md&amp;quot; &amp;quot;literal-erudite.lisp&amp;quot; :output-type :markdown))))
 :name &amp;quot;inotify-erudite&amp;quot;)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then I make the markdown file to be live-rendered in the browser.
I used impatient-mode for Emacs (see &lt;a href=&#34;http://wikemacs.org/wiki/Markdown#Live_preview_as_you_type&#34;&gt;Wikemacs&lt;/a&gt;) with the help of &lt;code&gt;M-x auto-revert-mode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Kuddos to Mariano Montone!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Common Lisp Macros By Example Tutorial</title>
      <link>/blog/common-lisp-macros-by-example-tutorial/</link>
      <pubDate>Mon, 02 Mar 2020 21:12:53 +0100</pubDate>
      
      <guid>/blog/common-lisp-macros-by-example-tutorial/</guid>
      <description>

&lt;p&gt;I have recently edited and somewhat expanded the macros page on the
Common Lisp Cookbook. I find it may more legible and reader friendly,
so I reproduce it below (however, I cut two parts so than you get the essential).&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;d better read it on the Cookbook: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/macros.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/macros.html&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;The word &lt;em&gt;macro&lt;/em&gt; is used generally in computer science to mean a syntactic extension to a programming language. (Note: The name comes from the word &amp;ldquo;macro-instruction,&amp;rdquo; which was a useful feature of many second-generation assembly languages. A macro-instruction looked like a single instruction, but expanded into a sequence of actual instructions. The basic idea has since been used many times, notably in the C preprocessor. The name &amp;ldquo;macro&amp;rdquo; is perhaps not ideal, since it connotes nothing relevant to what it names, but we&amp;rsquo;re stuck with it.) Although many languages have a macro facility, none of them are as powerful as Lisp&amp;rsquo;s. The basic mechanism of Lisp macros is simple, but has subtle complexities, so learning your way around it takes a bit of practice.&lt;/p&gt;

&lt;h1 id=&#34;how-macros-work&#34;&gt;How Macros Work&lt;/h1&gt;

&lt;p&gt;A macro is an ordinary piece of Lisp code that operates on &lt;em&gt;another piece of putative Lisp code,&lt;/em&gt; translating it into (a version closer to) executable Lisp. That may sound a bit complicated, so let&amp;rsquo;s give a simple example. Suppose you want a version of &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/s_setq.htm&#34;&gt;&lt;code&gt;setq&lt;/code&gt;&lt;/a&gt; that sets two variables to the same value. So if you write&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setq2 x y (+ z 3))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;when &lt;code&gt;z&lt;/code&gt;=8 then both &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are set to 11. (I can&amp;rsquo;t think of any use for this, but it&amp;rsquo;s just an example.)&lt;/p&gt;

&lt;p&gt;It should be obvious that we can&amp;rsquo;t define &lt;code&gt;setq2&lt;/code&gt; as a function. If &lt;code&gt;x&lt;/code&gt;=50 and &lt;code&gt;y&lt;/code&gt;=&lt;em&gt;-5&lt;/em&gt;, this function would receive the values 50, &lt;em&gt;-5&lt;/em&gt;, and 11; it would have no knowledge of what variables were supposed to be set. What we really want to say is, When you (the Lisp system) see:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setq2 v1 v2 e)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then treat it as equivalent to:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(progn
  (setq v1 e)
  (setq v2 e))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Actually, this isn&amp;rsquo;t quite right, but it will do for now. A macro allows us to do precisely this, by specifying a program for transforming the input pattern &lt;code&gt;(setq2 &lt;i&gt;v&lt;sub&gt;1&lt;/sub&gt;&lt;/i&gt; &lt;i&gt;v&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt; &lt;i&gt;e&lt;/i&gt;)&lt;/code&gt; into the output pattern &lt;code&gt;(progn ...)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;quote&#34;&gt;Quote&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s how we could define the &lt;code&gt;setq2&lt;/code&gt; macro:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setq2 (v1 v2 e)
  (list &#39;progn (list &#39;setq v1 e) (list &#39;setq v2 e)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It takes as parameters two variables and one expression.&lt;/p&gt;

&lt;p&gt;Then it returns a piece of code. In Lisp, because code is represented
as lists, we can simply return a list that represents code.&lt;/p&gt;

&lt;p&gt;We also use the &lt;em&gt;quote&lt;/em&gt;: each &lt;em&gt;quoted&lt;/em&gt; symbol evaluates to itself, aka
it is returned as is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(quote foo bar baz)&lt;/code&gt; returns &lt;code&gt;(foo bar baz)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the quote character, &lt;code&gt;&#39;&lt;/code&gt;, is a shortcut for &lt;code&gt;quote&lt;/code&gt;, a &lt;em&gt;special operator&lt;/em&gt; (not a function nor a macro, but one of a few special operators forming the core of Lisp).&lt;/li&gt;
&lt;li&gt;so, &lt;code&gt;&#39;foo&lt;/code&gt; evaluates to &lt;code&gt;foo&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, our macro retourns the following bits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the symbol &lt;code&gt;progn&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;a second list, that contains

&lt;ul&gt;
&lt;li&gt;the symbol &lt;code&gt;setq&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the variable &lt;code&gt;v1&lt;/code&gt;: note that the variable is not evaluated inside the macro!&lt;/li&gt;
&lt;li&gt;the expression &lt;code&gt;e&lt;/code&gt;: it is not evaluated either!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;a second list, with &lt;code&gt;v2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter v1 1)
(defparameter v2 2)
(setq2 v1 v2 3)
;; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can check, &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt; were set to &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;macroexpand&#34;&gt;Macroexpand&lt;/h2&gt;

&lt;p&gt;We must start writing a macro when we know what code we want to
generate. Once we&amp;rsquo;ve begun writing one, it becomes very useful to
check effectively what code does the macro generate. The function for
that is &lt;code&gt;macroexpand&lt;/code&gt;. It is a function, and we give it some code, as
a list (so, we quote the code snippet we give it):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(macroexpand &#39;(setq2 v1 v2 3))
;; (PROGN (SETQ V1 3) (SETQ V2 3))
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yay, our macro expands to the code we wanted!&lt;/p&gt;

&lt;p&gt;More interestingly:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(macroexpand &#39;(setq2 v1 v2 (+ z 3)))
;; (PROGN (SETQ V1 (+ z 3)) (SETQ V2 (+ z 3)))
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can confirm that our expression &lt;code&gt;e&lt;/code&gt;, here &lt;code&gt;(+ z 3)&lt;/code&gt;, was not
evaluated. We will see how to control the evaluation of arguments with
the comma: &lt;code&gt;,&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note: with Slime, you can call macroexpand by putting the cursor at
the left of the parenthesis of the s-expr to expand and call the function&lt;code&gt;M-x
slime-macroexpand-[1,all]&lt;/code&gt;, or &lt;code&gt;C-c M-m&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;[|](setq2 v1 v2 3)
;^ cursor
; C-c M-m
; =&amp;gt;
; (PROGN (SETQ V1 3) (SETQ V2 3))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;macros-vs-functions&#34;&gt;Macros VS functions&lt;/h2&gt;

&lt;p&gt;Our macro is very close to the following function definition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun setq2-function (v1 v2 e)
  (list &#39;progn (list &#39;setq v1 e) (list &#39;setq v2 e)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we evaluated &lt;code&gt;(setq2-function &#39;x &#39;y &#39;(+ z 3))&lt;/code&gt; (note that each
argument is &lt;em&gt;quoted&lt;/em&gt;, so it isn&amp;rsquo;t evaluated when we call the
function), we would get&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(progn (setq x (+ z 3)) (setq y (+ z 3)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a perfectly ordinary Lisp computation, whose sole point of interest is that its output is a piece of executable Lisp code. What &lt;code&gt;defmacro&lt;/code&gt; does is create this function implicitly and make sure that whenever an expression of the form &lt;code&gt;(setq2 x y (+ z 3))&lt;/code&gt; is seen, &lt;code&gt;setq2-function&lt;/code&gt; is called with the pieces of the form as arguments, namely &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;(+ z 3)&lt;/code&gt;. The resulting piece of code then replaces the call to &lt;code&gt;setq2&lt;/code&gt;, and execution resumes as if the new piece of code had occurred in the first place. The macro form is said to &lt;em&gt;expand&lt;/em&gt; into the new piece of code.&lt;/p&gt;

&lt;h2 id=&#34;evaluation-context&#34;&gt;Evaluation context&lt;/h2&gt;

&lt;p&gt;This is all there is to it, except, of course, for the myriad subtle consequences. The main consequence is that &lt;em&gt;run time for the &lt;code&gt;setq2&lt;/code&gt; macro&lt;/em&gt; is &lt;em&gt;compile time for its context.&lt;/em&gt; That is, suppose the Lisp system is compiling a function, and midway through it finds the expression &lt;code&gt;(setq2 x y (+ z 3))&lt;/code&gt;. The job of the compiler is, of course, to translate source code into something executable, such as machine language or perhaps byte code. Hence it doesn&amp;rsquo;t execute the source code, but operates on it in various mysterious ways. However, once the compiler sees the &lt;code&gt;setq2&lt;/code&gt; expression, it must suddenly switch to executing the body of the &lt;code&gt;setq2&lt;/code&gt; macro. As I said, this is an ordinary piece of Lisp code, which can in principle do anything any other piece of Lisp code can do. That means that when the compiler is running, the entire Lisp (run-time) system must be present.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll stress this once more: at compile-time, you have the full language at your disposal.&lt;/p&gt;

&lt;p&gt;Novices often make the following sort of mistake. Suppose that the &lt;code&gt;setq2&lt;/code&gt; macro needs to do some complex transformation on its &lt;code&gt;e&lt;/code&gt; argument before plugging it into the result. Suppose this transformation can be written as a Lisp procedure &lt;code&gt;some-computation&lt;/code&gt;. The novice will often write:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setq2 (v1 v2 e)
  (let ((e1 (some-computation e)))
    (list &#39;progn (list &#39;setq v1 e1) (list &#39;setq v2 e1))))

(defmacro some-computation (exp) ...) ;; _Wrong!_
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The mistake is to suppose that once a macro is called, the Lisp system enters a &amp;ldquo;macro world,&amp;rdquo; so naturally everything in that world must be defined using &lt;code&gt;defmacro&lt;/code&gt;. This is the wrong picture. The right picture is that &lt;code&gt;defmacro&lt;/code&gt; enables a step into the &lt;em&gt;ordinary Lisp world&lt;/em&gt;, but in which the principal object of manipulation is Lisp code. Once that step is taken, one uses ordinary Lisp function definitions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setq2 (v1 v2 e)
  (let ((e1 (some-computation e)))
    (list &#39;progn (list &#39;setq v1 e1) (list &#39;setq v2 e1))))

(defun some-computation (exp) ...) ;; _Right!_
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One possible explanation for this mistake may be that in other languages, such as C, invoking a preprocessor macro &lt;em&gt;does&lt;/em&gt; get you into a different world; you can&amp;rsquo;t run an arbitrary C program. It might be worth pausing to think about what it might mean to be able to.&lt;/p&gt;

&lt;p&gt;Another subtle consequence is that we must spell out how the arguments to the macro get distributed to the hypothetical behind-the-scenes function (called &lt;code&gt;setq2-function&lt;/code&gt; in my example). In most cases, it is easy to do so: In defining a macro, we use all the usual &lt;code&gt;lambda&lt;/code&gt;-list syntax, such as &lt;code&gt;&amp;amp;optional&lt;/code&gt;, &lt;code&gt;&amp;amp;rest&lt;/code&gt;, &lt;code&gt;&amp;amp;key&lt;/code&gt;, but what gets bound to the formal parameters are pieces of the macro form, not their values (which are mostly unknown, this being compile time for the macro form). So if we defined a macro thus:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro foo (x &amp;amp;optional y &amp;amp;key (cxt &#39;null)) ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;em&gt;If we call it thus &amp;hellip;&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;The parameters&amp;rsquo; values are &amp;hellip;&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(foo a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x=a&lt;/code&gt;, &lt;code&gt;y=nil&lt;/code&gt;, &lt;code&gt;cxt=null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(foo (+ a 1) (- y 1))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x=(+ a 1)&lt;/code&gt;, &lt;code&gt;y=(- y 1)&lt;/code&gt;, &lt;code&gt;cxt=null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(foo a b :cxt (zap zip))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x=a&lt;/code&gt;, &lt;code&gt;y=b&lt;/code&gt;, &lt;code&gt;cxt=(zap zip)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Note that the values of the variables are the actual expressions &lt;code&gt;(+ a 1)&lt;/code&gt; and &lt;code&gt;(zap zip)&lt;/code&gt;. There is no requirement that these expressions&amp;rsquo; values be known, or even that they have values. The macro can do anything it likes with them. For instance, here&amp;rsquo;s an even more useless variant of &lt;code&gt;setq&lt;/code&gt;: &lt;code&gt;(setq-reversible &lt;i&gt;e&lt;sub&gt;1&lt;/sub&gt;&lt;/i&gt; &lt;i&gt;e&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt; &lt;i&gt;d&lt;/i&gt;)&lt;/code&gt; behaves like &lt;code&gt;(setq &lt;i&gt;e&lt;sub&gt;1&lt;/sub&gt;&lt;/i&gt; &lt;i&gt;e&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;)&lt;/code&gt; if &lt;i&gt;d=&lt;/i&gt;&lt;code&gt;:normal&lt;/code&gt;, and behaves like &lt;code&gt;(setq &lt;i&gt;e&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt; &lt;i&gt;e&lt;sub&gt;1&lt;/sub&gt;&lt;/i&gt;)&lt;/code&gt; if &lt;em&gt;d=&lt;/em&gt;&lt;code&gt;:backward&lt;/code&gt;. It could be defined thus:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setq-reversible (e1 e2 direction)
  (case direction
    (:normal (list &#39;setq e1 e2))
    (:backward (list &#39;setq e2 e1))
    (t (error &amp;quot;Unknown direction: ~a&amp;quot; direction))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;rsquo;s how it expands:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(macroexpand &#39;(setq-reversible x y :normal))
(SETQ X Y)
T
(macroexpand &#39;(setq-reversible x y :backward))
(SETQ Y X)
T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And with a wrong direction:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(macroexpand &#39;(setq-reversible x y :other-way-around))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We get an error and are prompted into the debugger!&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll see the backquote and comma mechanism in the next section, but
here&amp;rsquo;s a fix:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setq-reversible (v1 v2 direction)
  (case direction
    (:normal (list &#39;setq v1 v2))
    (:backward (list &#39;setq v2 v1))
    (t `(error &amp;quot;Unknown direction: ~a&amp;quot; ,direction))))
    ;; ^^ backquote                    ^^ comma: get the value inside the backquote.

(macroexpand &#39;(SETQ-REVERSIBLE v1 v2 :other-way-around))
;; (ERROR &amp;quot;Unknown direction: ~a&amp;quot; :OTHER-WAY-AROUND)
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now when we call &lt;code&gt;(setq-reversible v1 v2 :other-way-around)&lt;/code&gt; we still get the
error and the debugger, but at least not when using &lt;code&gt;macroexpand&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&#34;2-backquote&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;backquote-and-comma&#34;&gt;Backquote and comma&lt;/h1&gt;

&lt;p&gt;Before taking another step, we need to introduce a piece of Lisp notation that is indispensable to defining macros, even though technically it is quite independent of macros. This is the &lt;em&gt;backquote facility&lt;/em&gt;. As we saw above, the main job of a macro, when all is said and done, is to define a piece of Lisp code, and that means evaluating expressions such as &lt;code&gt;(list &#39;prog (list &#39;setq ...) ...)&lt;/code&gt;. As these expressions grow in complexity, it becomes hard to read them and write them. What we find ourselves wanting is a notation that provides the skeleton of an expression, with some of the pieces filled in with new expressions. That&amp;rsquo;s what backquote provides. Instead of the the &lt;code&gt;list&lt;/code&gt; expression given above, one writes&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  `(progn (setq ,v1 ,e) (setq ,v2 ,e))
;;^ backquote   ^   ^         ^   ^ commas
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The backquote (`) character signals that in the expression that follows, every subexpression &lt;em&gt;not&lt;/em&gt; preceded by a comma is to be quoted, and every subexpression preceded by a comma is to be evaluated.&lt;/p&gt;

&lt;p&gt;You can think of it, and use it, as data interpolation:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;`(v1 = ,v1) ;; =&amp;gt; (V1 = 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s mostly all there is to backquote. There are just two extra items to point out.&lt;/p&gt;

&lt;h3 id=&#34;comma-splice&#34;&gt;Comma-splice ,@&lt;/h3&gt;

&lt;p&gt;First, if you write &amp;ldquo;&lt;code&gt;,@e&lt;/code&gt;&amp;rdquo; instead of &amp;ldquo;&lt;code&gt;,e&lt;/code&gt;&amp;rdquo; then the value of &lt;em&gt;e&lt;/em&gt; is &lt;em&gt;spliced&lt;/em&gt; (or &amp;ldquo;joined&amp;rdquo;, &amp;ldquo;combined&amp;rdquo;, &amp;ldquo;interleaved&amp;rdquo;) into the result. So if &lt;code&gt;v&lt;/code&gt; equals &lt;code&gt;(oh boy)&lt;/code&gt;, then&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(zap ,@v ,v)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;evaluates to&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(zap oh boy (oh boy))
;;   ^^^^^ elements of v (two elements), spliced.
;;          ^^ v itself (a list)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second occurrence of &lt;code&gt;v&lt;/code&gt; is replaced by its value. The first is replaced by the elements of its value. If &lt;code&gt;v&lt;/code&gt; had had value &lt;code&gt;()&lt;/code&gt;, it would have disappeared entirely: the value of &lt;code&gt;(zap ,@v ,v)&lt;/code&gt; would have been &lt;code&gt;(zap ())&lt;/code&gt;, which is the same as &lt;code&gt;(zap nil)&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;quote-comma&#34;&gt;Quote-comma &amp;lsquo;,&lt;/h3&gt;

&lt;p&gt;When we are inside a backquote context and we want to print an
expression literally, we have no choice but to use the combination of
quote and comma:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro explain-exp (exp)
  `(format t &amp;quot;~S = ~S&amp;quot; &#39;,exp ,exp))
  ;;                   ^^

(explain-exp (+ 2 3))
;; (+ 2 3) = 5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See by yourself:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Defmacro with no quote at all:
(defmacro explain-exp (exp)
  (format t &amp;quot;~a = ~a&amp;quot; exp exp))
(explain-exp v1)
;; V1 = V1

;; OK, with a backquote and a comma to get the value of exp:
(defmacro explain-exp (exp)
  ;; WRONG example
  `(format t &amp;quot;~a = ~a&amp;quot; exp ,exp))
(explain-exp v1)
;; =&amp;gt; error: The variable EXP is unbound.

;; We then must use quote-comma:
(defmacro explain-exp (exp)
  `(format t &amp;quot;~a = ~a&amp;quot; &#39;,exp ,exp))
(explain-exp (+ 1 2))
;; (+ 1 2) = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;nested-backquotes&#34;&gt;Nested backquotes&lt;/h3&gt;

&lt;p&gt;Second, one might wonder what happens if a backquote expression occurs inside another backquote. The answer is that the backquote becomes essentially unreadable and unwriteable; using nested backquote is usually a tedious debugging exercise. The reason, in my not-so-humble opinion, is that backquote is defined wrong. A comma pairs up with the innermost backquote when the default should be that it pairs up with the outermost. But this is not the place for a rant; consult your favorite Lisp reference for the exact behavior of nested backquote plus some examples.&lt;/p&gt;

&lt;h3 id=&#34;building-lists-with-backquote&#34;&gt;Building lists with backquote&lt;/h3&gt;

&lt;p&gt;[…]&lt;/p&gt;

&lt;h1 id=&#34;getting-macros-right&#34;&gt;Getting Macros Right&lt;/h1&gt;

&lt;p&gt;I said in the first section that my definition of &lt;code&gt;setq2&lt;/code&gt; wasn&amp;rsquo;t quite right, and now it&amp;rsquo;s time to fix it.&lt;/p&gt;

&lt;p&gt;Suppose we write &lt;code&gt;(setq2 x y (+ x 2))&lt;/code&gt;, when &lt;code&gt;x&lt;/code&gt;&lt;em&gt;=8&lt;/em&gt;. Then according to the definition given above, this form will expand into&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(progn
  (setq x (+ x 2))
  (setq y (+ x 2)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so that &lt;code&gt;x&lt;/code&gt; will have value 10 and &lt;code&gt;y&lt;/code&gt; will have value 12. Indeed, here&amp;rsquo;s its macroexpansion:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(macroexpand &#39;(setq2 x y (+ x 2)))
;;(PROGN (SETQ X (+ X 2)) (SETQ Y (+ X 2)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Chances are that isn&amp;rsquo;t what the macro is expected to do (although you never know). Another problematic case is &lt;code&gt;(setq2 x y (pop l))&lt;/code&gt;, which causes &lt;code&gt;l&lt;/code&gt; to be popped twice; again, probably not right.&lt;/p&gt;

&lt;p&gt;The solution is to evaluate the expression &lt;code&gt;e&lt;/code&gt; just once, save it in a temporary variable, and then set &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt; to it.&lt;/p&gt;

&lt;h2 id=&#34;gensym&#34;&gt;Gensym&lt;/h2&gt;

&lt;p&gt;To make temporary variables, we use the &lt;code&gt;gensym&lt;/code&gt; function, which returns a fresh variable guaranteed to appear nowhere else. Here is what the macro should look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro setq2 (v1 v2 e)
  (let ((tempvar (gensym)))
    `(let ((,tempvar ,e))
       (progn (setq ,v1 ,tempvar)
              (setq ,v2 ,tempvar)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now &lt;code&gt;(setq2 x y (+ x 2))&lt;/code&gt; expands to&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((#:g2003 (+ x 2)))
  (progn (setq x #:g2003) (setq y #:g2003)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here &lt;code&gt;gensym&lt;/code&gt; has returned the symbol &lt;code&gt;#:g2003&lt;/code&gt;, which prints in this funny way because it won&amp;rsquo;t be recognized by the reader. (Nor is there any need for the reader to recognize it, since it exists only long enough for the code that contains it to be compiled.)&lt;/p&gt;

&lt;p&gt;Exercise: Verify that this new version works correctly for the case &lt;code&gt;(setq2 x y (pop l1))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Exercise: Try writing the new version of the macro without using backquote. If you can&amp;rsquo;t do it, you have done the exercise correctly, and learned what backquote is for!&lt;/p&gt;

&lt;p&gt;The moral of this section is to think carefully about which expressions in a macro get evaluated and when. Be on the lookout for situations where the same expression gets plugged into the output twice (as &lt;code&gt;e&lt;/code&gt; was in my original macro design). For complex macros, watch out for cases where the order that expressions are evaluated differs from the order in which they are written. This is sure to trip up some user of the macro - even if you are the only user.&lt;a name=&#34;LtohTOCentry-4&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;what-macros-are-for&#34;&gt;What Macros are For&lt;/h1&gt;

&lt;p&gt;[…]&lt;/p&gt;

&lt;h1 id=&#34;see-also&#34;&gt;See also&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://medium.com/@MartinCracauer/a-gentle-introduction-to-compile-time-computing-part-1-d4d96099cea0&#34;&gt;A gentle introduction to Compile-Time Computing — Part 1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://medium.com/@MartinCracauer/a-gentle-introduction-to-compile-time-computing-part-3-scientific-units-8e41d8a727ca&#34;&gt;Safely dealing with scientific units of variables at compile time (a gentle introduction to Compile-Time Computing — part 3)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following video, from the series
&lt;a href=&#34;https://www.youtube.com/user/CBaggers/playlists&#34;&gt;&amp;ldquo;Little bits of Lisp&amp;rdquo;&lt;/a&gt;
by &lt;a href=&#34;https://github.com/cbaggers/&#34;&gt;cbaggers&lt;/a&gt;, is a two hours long talk
on macros, showing simple to advanced concepts such as compiler
macros:
&lt;a href=&#34;https://www.youtube.com/watch?v=ygKXeLKhiTI&#34;&gt;https://www.youtube.com/watch?v=ygKXeLKhiTI&lt;/a&gt;
It also shows how to manipulate macros (and their expansion) in Emacs.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=ygKXeLKhiTI&#34;&gt;&lt;img src=&#34;http://img.youtube.com/vi/ygKXeLKhiTI/0.jpg&#34; alt=&#34;video&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Yes Google Uses and Hacks on Common Lisp</title>
      <link>/blog/yes-google-develops-common-lisp/</link>
      <pubDate>Mon, 02 Mar 2020 20:47:32 +0100</pubDate>
      
      <guid>/blog/yes-google-develops-common-lisp/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/ITA_Software&#34;&gt;ITA Software&lt;/a&gt;, owned by
Google, the airfare search and pricing system that is still used by
companies such as Kayak.com or Orbitz, is a well-known example of a
successful industrial and large Common Lisp software.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re legitimate to wonder if they still run it (they do), if Google
develops more CL software (I don&amp;rsquo;t know), or if they put resources to
improve a CL implementation: they do.&lt;/p&gt;

&lt;p&gt;According to &lt;a href=&#34;https://mstmetent.blogspot.com/2020/01/sbcl20-in-vienna-last-month-i-attended.html:&#34;&gt;https://mstmetent.blogspot.com/2020/01/sbcl20-in-vienna-last-month-i-attended.html:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Doug Katzman talked about his work at Google getting SBCL to work with Unix better. For those of you who don&amp;rsquo;t know, he&amp;rsquo;s done a lot of work on SBCL over the past couple of years, not only adding a lot of new features to the GC and making it play better with applications which have alien parts to them, but also has done a tremendous amount of cleanup on the internals and has helped SBCL become even more Sanely Bootstrappable. That&amp;rsquo;s a topic for another time, and I hope Doug or Christophe will have the time to write up about the recent improvements to the process, since it really is quite interesting.&lt;/p&gt;

&lt;p&gt;Anyway, what Doug talked about was his work on making SBCL more amenable to external debugging tools, such as gdb and external profilers. It seems like they interface with aliens a lot from Lisp at Google, so it&amp;rsquo;s nice to have backtraces from alien tools understand Lisp. It turns out a lot of prerequisite work was needed to make SBCL play nice like this, including implementing a non-moving GC runtime, so that Lisp objects and especially Lisp code (which are normally dynamic space objects and move around just like everything else) can&amp;rsquo;t evade the aliens and will always have known locations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now that&amp;rsquo;s in the wild, Common Lisp can go trendy again: Google uses and dedicates resources for Common Lisp!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Python VS Common Lisp Workflow and Ecosystem</title>
      <link>/blog/pythonvslisp-workflow-and-ecosystem/</link>
      <pubDate>Wed, 06 Nov 2019 15:21:53 +0100</pubDate>
      
      <guid>/blog/pythonvslisp-workflow-and-ecosystem/</guid>
      <description>&lt;p&gt;please see &lt;a href=&#34;/pythonvslisp/&#34;&gt;Python VS Common Lisp&lt;/a&gt; (it&amp;rsquo;s a static page you can find in the menu).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Snippet: Manipulating Rows and Columns With ClAWK</title>
      <link>/blog/snippet-manipulating-rows-and-columns-with-clawk/</link>
      <pubDate>Mon, 04 Nov 2019 18:40:52 +0100</pubDate>
      
      <guid>/blog/snippet-manipulating-rows-and-columns-with-clawk/</guid>
      <description>&lt;p&gt;I just discovered &lt;a href=&#34;https://github.com/sharplispers/clawk&#34;&gt;clawk&lt;/a&gt;, that
seems to originate from
&lt;a href=&#34;https://github.com/lispbuilder/lispbuilder&#34;&gt;lispbuilder-clawk&lt;/a&gt;. Its
last commit dates from 2011, typical from Lisp and that&amp;rsquo;s OK,
libraries have the right to be done, it has no useful README nor
documentation, but we can see its use in &lt;a href=&#34;https://github.com/sharplispers/clawk/blob/master/clawktest.lisp&#34;&gt;the
tests&lt;/a&gt;,
and the library is easily discoverable.&lt;/p&gt;

&lt;p&gt;This library seems perfect to manipulate data in rows and columns.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s have a quick look with this dummy txt file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1 Alice 40 40
2 Bob 39 50
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I had a conflict when &lt;code&gt;use&lt;/code&gt;-ing clawk, which I resolved by not
accepting the change in the debugger.&lt;/p&gt;

&lt;p&gt;We parse all lines, give a name to the space-delimited fields, and print them back:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(for-file-lines (&amp;quot;test.txt&amp;quot;)
    (with-fields ((a b c d))
        ($print a b c d)))

1 Alice 40 40
2 Bob 39 50
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s multiply the two last fields. If we use the regular &lt;code&gt;*&lt;/code&gt; operator, we get a
type error because fields are extracted as strings by default. We then
use &lt;code&gt;$*&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(for-file-lines (&amp;quot;test.txt&amp;quot;)
    (with-fields ((id name payrate hrsworked))
        (declare (ignore id))
        ($print name ($* payrate hrsworked))))
Alice 1600
Bob 1950
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can change the field separator with a string or a regexp, with the
no surprising &lt;code&gt;clawk:*fs*&lt;/code&gt; variable (&lt;code&gt;FS&lt;/code&gt; in awk):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(for-file-lines (&amp;quot;test.txt&amp;quot;)
    (let ((clawk:*fs* &amp;quot;-&amp;quot;))
        (with-fields ((a b c))
        ($print a))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And… that&amp;rsquo;s all folks. Another tool to keep in our toolbelt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more about awk: &lt;a href=&#34;https://www.gnu.org/software/gawk/manual/html_node/&#34;&gt;https://www.gnu.org/software/gawk/manual/html_node/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Python VS Common Lisp, workflow and ecosystem</title>
      <link>/pythonvslisp/</link>
      <pubDate>Wed, 30 Oct 2019 07:51:49 +0100</pubDate>
      
      <guid>/pythonvslisp/</guid>
      <description>

&lt;!-- started = &#34;2017-02-05T07:51:49+01:00&#34; --&gt;

&lt;!-- finished = &#34;2019-10-30&#34; --&gt;

&lt;p&gt;I learned Java and C at school, I learned Python by myself and it was
a relief. After 8 years working and doing side projects in Python and
JavaScript (mostly web dev, Django/Flask/AngularJS/Vuejs), I am not
satisfied anymore by the overall experience so I&amp;rsquo;m making Common Lisp my
language of choice.&lt;/p&gt;

&lt;p&gt;I am not here to compare languages themselves, but their inherent
workflow and their ecosystem. This is the article I wish I had read
earlier, when I was interested in Lisp but was a bit puzzled, because
the Lisp way always seemed different, and I couldn&amp;rsquo;t find many
voices to explain it. The Python way may not be the
most practical or effective, Common Lisp might not be a dead language. I find many &amp;ldquo;workflow
fixes&amp;rdquo;, overall improvements and hackerish possibilities on the CL side, even if sometimes the
Python tooling is superior.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s dive in.&lt;/p&gt;

&lt;p&gt;and thanks to the proofreaders.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#development-process&#34;&gt;Development process&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#interactivity&#34;&gt;Interactivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#editing-code&#34;&gt;Editing code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#running-testing-programs&#34;&gt;Running, testing programs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#typing&#34;&gt;Typing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#refactoring&#34;&gt;Refactoring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#libraries&#34;&gt;Libraries&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#library-management&#34;&gt;Library management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#state-of-the-libraries&#34;&gt;State of the libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#templates&#34;&gt;Templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deployment-shipping&#34;&gt;Deployment, Shipping&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#performance&#34;&gt;Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conclusion&#34;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#appendix-faq&#34;&gt;Appendix: FAQ&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#are-there-no-iterators&#34;&gt;Are there no iterators ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#can-i-define-my-own-operator-like-in-an-oo-language&#34;&gt;Can I define my own &lt;code&gt;+&lt;/code&gt; operator like in an OO language ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#to-which-extent-can-lisp-be-compiled-with-all-its-dynamic-nature-garbage-collection-macros-and-what-else&#34;&gt;To which extent can Lisp be compiled, with all its dynamic nature, garbage collection, macros and what else ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#but-what-is-common-lisp-good-for-really&#34;&gt;But what is Common Lisp good for, really ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#so-why-is-cl-not-more-popular&#34;&gt;So why is CL not more popular ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;development-process&#34;&gt;Development process&lt;/h1&gt;

&lt;h2 id=&#34;interactivity&#34;&gt;Interactivity&lt;/h2&gt;

&lt;p&gt;In &lt;em&gt;Python&lt;/em&gt;, we typically restart everything at each code change, we use
 breakpoints: this takes some time, I find it too repetitive and boring, it requires to
 re-manipulate data to re-reach the state we were at to analyze and
 debug our program. We might figure out a non-standard,
 more interactive way, but still: a web server needs to restart,
 object instances don&amp;rsquo;t get updated after a class definition. We can get a prompt on an error (&lt;code&gt;-m pdb&lt;/code&gt;), some tools include it (Werkzeug): a sign that it is a good thing to have. Unfortunately, it is not built-in, as in CL.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Common Lisp&lt;/em&gt;, everything is much more interactive in the REPL. Even
developing web apps. On an error, we get an interactive debugger with
the stacktrace in our editor, we press &lt;code&gt;v&lt;/code&gt; and voilà, we are at the
problematic line. We can of course catch errors to avoid the debugger, or disable it with global settings. We can resume the program execution from any stackframe. No process needs to restart. The variables
that we define on the REPL stay here. If we change a class definition
(say, we remove a field), existing instances get (lazily) updated.&lt;/p&gt;

&lt;p&gt;The Lisp REPL is part of the development process, it is not only used
for exploration and debugging. It&amp;rsquo;s fun, it&amp;rsquo;s a productive boost, and
it allows to catch errors earlier, both because we try functions
earlier, and because we get type warnings when we compile the file or
the current function (yes, we can compile a single function).&lt;/p&gt;

&lt;p&gt;Now, the cost is that one must learn to play with this live data. We
might come to a state that doesn&amp;rsquo;t reflect the code anymore, so we&amp;rsquo;ll
write our own &amp;ldquo;reset&amp;rdquo; functions or just restart the lisp image.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s &lt;a href=&#34;https://www.youtube.com/embed/CNFr7zIfyeM&#34;&gt;a video&lt;/a&gt; where the developer defines a dummy interface, makes it
fail, develops it, and tests it, all quickly by interacting with the REPL.&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/CNFr7zIfyeM&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;In &lt;a href=&#34;https://www.youtube.com/watch?v=jBBS4FeY7XM&#34;&gt;this video&lt;/a&gt; I show how we can interactively fix a function and resume the program from this precise point in the call stack, without re-starting the whole, time-consuming operation.&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/jBBS4FeY7XM&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;img src=&#34;/images/debugging-python-VS-lisp.png&#34; alt=&#34;Debugging a complex stacktrace in Python VS Common Lisp (author unknown)&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;editing-code&#34;&gt;Editing code&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Python&lt;/em&gt;: we edit code line by line, paragraph by paragraph. We can
try out half-backed editor plugins to edit code by semantic units. Sometimes we
must even pay attention to add a couple whitespace there, remove one
there. We are far from the immediate interactive feedback of the hacker&amp;rsquo;s
vision &amp;ldquo;Inventing on Principles&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Common Lisp&lt;/em&gt;: we edit code by semantic units. I love emacs&amp;rsquo; &lt;a href=&#34;http://oremacs.com/lispy/&#34;&gt;lispy
mode&lt;/a&gt;, which is weird at first of course,
but so convenient. We can navigate to expressions back and forth, we
can delete a whole &amp;ldquo;if&amp;rdquo; expression with a keypress, indentation is
automatic, etc. There are &lt;a href=&#34;http://wikemacs.org/wiki/Lisp_editing&#34;&gt;other emacs plugins&lt;/a&gt;. &lt;a href=&#34;https://shaunlebron.github.io/parinfer/&#34;&gt;Parinfer&lt;/a&gt; is appreciated in other editors too.&lt;/p&gt;

&lt;p&gt;Actually, we edit code by parenthesis units, which doesn&amp;rsquo;t carry as
much meaning as an Abstract Syntax Tree. For a real AST, we&amp;rsquo;d need a
code walker (like &lt;a href=&#34;https://github.com/s-expressionists/Concrete-Syntax-Tree&#34;&gt;Concrete-Syntax-Tree&lt;/a&gt;). But since Lisp&amp;rsquo;s syntax is based on parenthesis, in
practice the experience is similar.&lt;/p&gt;

&lt;!-- Some libraries are being built on the code walker: https://github.com/FiV0/cl-navigate-sc --&gt;

&lt;p&gt;I had a try on writing a little plugin to help editing Python code by manipulating
the AST (&lt;a href=&#34;https://github.com/vindarel/redbaron4emacs&#34;&gt;red4e&lt;/a&gt;).  We
first need an AST parser. There was a couple for Python 2, another one
for Python 3 without type annotations, eventually one emerged a couple
years later: these are signs of an unstable language and ecosystem, and it is more work
required by the developer. I went the simple way by calling each
function into a new Python process, which is of course too
slow. &lt;a href=&#34;https://github.com/abingham/traad&#34;&gt;traad&lt;/a&gt; is a better project,
it can do much more but still, it&amp;rsquo;s difficult to answer questions like
cross-referencing: &amp;ldquo;who calls this function&amp;rdquo; or &amp;ldquo;who does this
function call&amp;rdquo;, which are built-in in
SLIME. &lt;a href=&#34;https://en.wikipedia.org/wiki/SLIME&#34;&gt;SLIME&lt;/a&gt; is like the Language
Server Protocol for Common Lisp in Emacs, its backend Swank being
editor-agnostic.&lt;/p&gt;

&lt;p&gt;Maybe other editors and proprietary ones come with a better
experience, at the cost of freedom, money, configuration time and
memory and CPU resources. If I have the choice, I prefer to not go
this route, and choose a better platform from the start.&lt;/p&gt;

&lt;p&gt;Traad is built around a client-http server approach, this is the idea
behind LSP…  this reminds me of the architecture of SLIME!
It has a backend, Swank, and a client (SLIME for Emacs, SLIMA for Atom,…).
It thus has a modern architecture since its
inception :) It is moreover based on a stable language whose syntax
can not rot and has decades of development behind it, so we can be
confident about the tool. Saying this because it&amp;rsquo;s hard to grasp what
SLIME is at the beginning.&lt;/p&gt;

&lt;p&gt;SLIME itself is tied to Emacs, and thus a newcomer can find the UI
unpractical. Swank though can be used outside of Emacs, and it is for
example for Atom&amp;rsquo;s &lt;a href=&#34;https://github.com/neil-lindquist/SLIMA/&#34;&gt;SLIMA&lt;/a&gt;,
which now has all the most important SLIME features: REPL, integrated
debugger, jump to definition, autocompletion, interactive object
inspection, and more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/editor-support.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/editor-support.html&lt;/a&gt; (Eclipse, Lem, Jupyter Notebook,…)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/tarsius/paren-face/&#34;&gt;&lt;img src=&#34;https://raw.githubusercontent.com/tarsius/paren-face/master/parentheses.png&#34; alt=&#34;&#34; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;running-testing-programs&#34;&gt;Running, testing programs&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Python&lt;/em&gt;: the default workflow is to run commands in the
terminal. Scroll, read the output, copy-paste manually (or use the
non-UX-optimal termux or a terminal inside emacs), go back to your
editor. Type commands without completion, type the whole path to a
single unit test (&lt;code&gt;pytest path/to/test.py::foo&lt;/code&gt;), or configure your
editor and find a good plugin that is compatible with your test runner (I
can&amp;rsquo;t use the excellent nose-mode :( ).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Common Lisp&lt;/em&gt;: the default workflow is to do everything interactively
into the REPL, but some people still use a
write-compile-run approach. Consequently there is built-in completion for
everything. We don&amp;rsquo;t have to use the shell (except from once in a
while to run global tests or build the system) and that&amp;rsquo;s a good
thing. There is an interactive debugger. We can interactively fix and re-run code and
tests.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s &lt;a href=&#34;https://www.youtube.com/embed/KsHxgP3SRTs&#34;&gt;a quick demo&lt;/a&gt; on how to interactively fix failing tests:&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/KsHxgP3SRTs&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Running and debugging on a remote server: in Python, we usually rsync
sources and run tests manually, or start vim/emacs under tmux on the
server. We have to kill the app to reload it. In Common Lisp, we can
connect to the running, remote instance, write changes from the
comfort of our editor locally, hit &lt;code&gt;C-c C-c&lt;/code&gt; on a function to compile it
and see changes on the remote image. CL has more hackerish capacities
here, no doubt, and I find it attractive :)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more information on (remote) debugging: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/debugging.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a demo with a web app: &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/&#34;&gt;https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;watch Baggers working with OpenGL: &lt;a href=&#34;https://www.youtube.com/watch?v=a2tTpjGOhjw&amp;amp;index=20&amp;amp;list=RDxzTH_ZqaFKI&#34;&gt;https://www.youtube.com/watch?v=a2tTpjGOhjw&amp;amp;index=20&amp;amp;list=RDxzTH_ZqaFKI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a Minecraft game engine that you can change while playing: &lt;a href=&#34;https://github.com/gmasching/sucle&#34;&gt;https://github.com/gmasching/sucle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;typing&#34;&gt;Typing&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Python&lt;/em&gt;: we catch a lot of type errors in production, and/or we have
to write a lot more unit tests. Hope we agree on this.&lt;/p&gt;

&lt;p&gt;Now we can improve the situation somehow with type annotations,
however it has the cons of being an after-thought: it is not stable
(differences between Python versions), not well integrated
(we have to run another command, choose between mypy, the new typing
module, pyre), it is not interactive, we need to configure our IDE, it
adds a start-up penalty (which might or might not be important).&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Common Lisp&lt;/em&gt;, particularly with SBCL, we get a lot of type errors
or warnings at compile time. We can compile &lt;em&gt;a single function&lt;/em&gt;, and
thus have an immediate feedback.  We&amp;rsquo;re closer (not there, just
closer) to the &amp;ldquo;if it compiles, it works&amp;rdquo; situation (we know it runs,
since we constantly compile and try the functions). We can also create
our compound types and add type declarations to variables and
functions. It&amp;rsquo;s great, though it doesn&amp;rsquo;t do as much static checks as a
real typed language.&lt;/p&gt;

&lt;p&gt;Adding type declarations in well chosen places such as inner loops
also allows to gradually speed up the program where needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/type.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/type.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@MartinCracauer/static-type-checking-in-the-programmable-programming-language-lisp-79bb79eb068a&#34;&gt;Compile-time type checking in the programmable programming language Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;will &lt;a href=&#34;https://github.com/tarballs-are-good/coalton&#34;&gt;ML embedded into CL&lt;/a&gt;
help even more ?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;refactoring&#34;&gt;Refactoring&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Python&lt;/em&gt;: we can&amp;rsquo;t refactor code as we want. Decorators, context
managers: they have an interface and they are limited to what they
offer. You can&amp;rsquo;t do things a bit differently, you must comply to the
interface. That might be a feature, but I prefer not being
restricted. In my experience, this leads to code repetition whereas
in CL, we can refactor how we want, and we get a cleaner code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Common Lisp&lt;/em&gt;: there are similar patterns than in Python, but we can
escape them. We can use macros, be concise and do what we want. We can
have the decorator syntax with the cl-annot library, and any other by
writing our reader macros (they can bring triply-quoted docstrings,
string interpolation, infix notation, C syntax…). It&amp;rsquo;s not only macros
though. The polymorphism of the object system (or generic dispatch)
helps, and Lisp&amp;rsquo;s &amp;ldquo;moldability&amp;rdquo; in a whole allows us to refactor code
exactly how we want, to build a &amp;ldquo;Domain Specific Language&amp;rdquo; to express
what we want. Other language features than macros help here, like
closures or &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/functions.html#multiple-return-values-values-multiple-value-bind-and-nth-value&#34;&gt;multiple
values&lt;/a&gt;
(which are different, and safer for refactoring, than returning a tuple).&lt;/p&gt;

&lt;p&gt;Now, speaking about refactoring tools, they are better Python side. I
don&amp;rsquo;t know of a Lisp tool that allows to change all the code-base
according to the AST, maybe in a proprietary editor. There are
utilities to make local transformations, like &amp;ldquo;extract this expression
into a &lt;code&gt;let&lt;/code&gt; variable at the top of the function&amp;rdquo;, &amp;ldquo;transform a
function to a lambda equivalent&amp;rdquo; or the contrary, etc.&lt;/p&gt;

&lt;p&gt;(edit January, 2020: the language-agnostic tool &lt;a href=&#34;https://github.com/comby-tools/comby&#34;&gt;Comby&lt;/a&gt; will be useful here. I used it for syntactic manipulation, for example to replace a &lt;code&gt;(if (…) (progn …))&lt;/code&gt; by a &lt;code&gt;(when (…) …)&lt;/code&gt;). See &lt;a href=&#34;https://github.com/vindarel/colisper&#34;&gt;Colisper&lt;/a&gt; (a POC).&lt;/p&gt;

&lt;h1 id=&#34;libraries&#34;&gt;Libraries&lt;/h1&gt;

&lt;h2 id=&#34;library-management&#34;&gt;Library management&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;pip&lt;/em&gt;: use virtual environments (virtualenv, virtualenvwrapper, tox,
anaconda,…  or install per-user), pin dependencies (pip-tools, pipenv, poetry,
pyupdate,…). Debug problems due to
a third party library that didn&amp;rsquo;t pin its dependencies strictly
enough (happens at the wrong moment).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;quicklisp&lt;/em&gt;: think of it like Debian&amp;rsquo;s apt, shipping releases that
work together (that load together), and that we upgrade together, when we
want. If needed, we can still clone projects into
&lt;code&gt;~/quicklisp/local-projects/&lt;/code&gt; for a system-wide installation, or have
project-local dependencies with
&lt;a href=&#34;https://github.com/fukamachi/qlot&#34;&gt;Qlot&lt;/a&gt;.
Quicklisp is very slick. Libraries are installed at runtime, during
 our REPL session. We don&amp;rsquo;t have to reload the Lisp process.&lt;/p&gt;

&lt;p&gt;We are not even limited to Quicklisp any more (it can be limiting
because of its one month release cycle). The
&lt;a href=&#34;http://ultralisp.org/&#34;&gt;Ultralisp&lt;/a&gt; distribution builds every 5
minutes. &lt;a href=&#34;https://gitlab.common-lisp.net/clpm/clpm&#34;&gt;clpm&lt;/a&gt; is a package
manager with a traditional approach. One can publish his own Quicklisp
distribution, to provide a set of packages that are known to work
together.&lt;/p&gt;

&lt;h2 id=&#34;state-of-the-libraries&#34;&gt;State of the libraries&lt;/h2&gt;

&lt;p&gt;CL might have more libraries than you think, see the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome CL
list&lt;/a&gt;,
&lt;a href=&#34;http://quickdocs.org/&#34;&gt;http://quickdocs.org/&lt;/a&gt; or do a quick search on the net. I know I am
constantly surprised.&lt;/p&gt;

&lt;p&gt;But sure, the Python ecosystem is huge. A few remarks on the differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quicklisp has around 1500 packages, PyPI over than 170 000. It&amp;rsquo;s hard to imagine that there are a hundred times more useful libraries :D Even in CL we have duplication of libraries with a dozen of test frameworks.&lt;/li&gt;
&lt;li&gt;Quicklisp is a curated distribution, PyPI is not. That means that
libraries that don&amp;rsquo;t compile anymore are rejected (after a notice to
the maintainers), and that orphan projects&amp;rsquo; URL can be updated to
point to a community maintained one.&lt;/li&gt;
&lt;li&gt;Anybody can easily publish a library to PyPI on its own. Less so
with Quicklisp, one must open an issue (Ultralisp doesn&amp;rsquo;t have this limitation).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/numcl/numcl&#34;&gt;numcl&lt;/a&gt; is a Numpy clone.&lt;/li&gt;
&lt;li&gt;if needed, you can use &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#python&#34;&gt;py4cl and more&lt;/a&gt; to interface with Python.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An important remark, is that Common Lisp is a stable language, and
that the libraries play this game (I saw a deprecation feature staying
for 12 years). We can still run code that was written in the early 90&amp;rsquo;s.&lt;/p&gt;

&lt;p&gt;Lisp&amp;rsquo;s simpler, non-rotting syntax plays a good role on
stability. Caution: that doesn&amp;rsquo;t mean the implementations don&amp;rsquo;t
evolve, quite the contrary.&lt;/p&gt;

&lt;p&gt;In his appreciated article &lt;a href=&#34;http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/&#34;&gt;A Road to Common Lisp&lt;/a&gt;, the author writes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;as you learn Common Lisp and look for libraries, try to suppress the voice in the back of your head that says “This project was last updated six years ago? That’s probably abandoned and broken.” The stability of Common Lisp means that sometimes libraries can just be done, not abandoned, so don’t dismiss them out of hand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=17852194&#34;&gt;hacker news comments&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;templates&#34;&gt;Templates&lt;/h1&gt;

&lt;p&gt;Ever had headaches with Jinja ? Ever fought against Django
templates ? Ever abandoned to clean up a big mess of html and
templating code ? Used Jinja macros to factorize code ? Maybe you
turned to the good looking Jade (Pug). So you read another documentation,
you install tools to integrate it into your project. And now damn, no
more cross-files macros. You edit blocks of code whitespace by
whitespace. And in the end, your html may still not be valid…&lt;/p&gt;

&lt;p&gt;You might use Mako templates, but there&amp;rsquo;s something you can&amp;rsquo;t do.&lt;/p&gt;

&lt;p&gt;In CL, we can also use a Django-like templating engine, &lt;a href=&#34;https://github.com/mmontone/djula&#34;&gt;Djula&lt;/a&gt;
templates (despite its modest number
of stars, it is one of the most downloaded projects on Quicklisp).
The Mako equivalent would be &lt;a href=&#34;https://github.com/mmontone/ten&#34;&gt;Ten&lt;/a&gt;.
However, we can alternatively just use plain old Lisp, for example with
&lt;a href=&#34;https://github.com/ruricolist/spinneret/&#34;&gt;Spinneret&lt;/a&gt;. As a
consequence, we can factorize code as we always do (with spinneret functions or
lisp macros). We manipulate code as we always do. It even warns on
malformed html and has some neat features (it is clever about headers
levels, it can embed markdown, etc).&lt;/p&gt;

&lt;p&gt;Stuff like this is less possible with Python, because the language is
less flexible. The components libraries I have seen use strings inside
Python code.&lt;/p&gt;

&lt;h1 id=&#34;deployment-shipping&#34;&gt;Deployment, Shipping&lt;/h1&gt;

&lt;p&gt;Shipping an app, even more a web app, in &lt;em&gt;Python&lt;/em&gt; (and JS) is
tedious. There are no default way to ship a self-contained
executable. Current projects aiming at fixing that can work… and may not.&lt;/p&gt;

&lt;p&gt;So the current solution is to turn to containers. They&amp;rsquo;re the Big
Thing, but we still need to spend hours on reading resources, building
the Docker file, the deployment pipeline, fixing bugs, updating the
stack, accepting security holes, etc. Hours we could put on our
app. With Docker though, users still can&amp;rsquo;t download a binary.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Common Lisp&lt;/em&gt;: we (re)discover the joy of a compiled language. We
compile our program to machine code, the binary embeds the run-time, the
debugger, the web server, the static assets, and we ship it. We run it on
the server and we can access it from the outside straight away.&lt;/p&gt;

&lt;p&gt;An SBCL image of a non-trivial web project will weight ± 20 to 30MB
(with core compression). For a lighter binary (not that I care
personally), we could try ECL (that compiles to C), or use
tree-shakers of proprietary implementations (LispWorks, Allegro).&lt;/p&gt;

&lt;p&gt;We can still benefit from Docker if needed, of course.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deployment process in Python&lt;/em&gt;: install Python and pip, install pip
dependencies and their system requirements and be prepared for errors (or try non-standard tools,
like Platter), configure a server for static files (nginx, whitenoise), run a
WSGI web server,…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deployment in CL&lt;/em&gt;: build your binary, send it to the server, run
it. Configure nginx eventually. We can compile and include assets into
the image (see &lt;a href=&#34;https://github.com/eudoxia0/rock&#34;&gt;Rock&lt;/a&gt;).&lt;/p&gt;

&lt;h1 id=&#34;performance&#34;&gt;Performance&lt;/h1&gt;

&lt;p&gt;Python is notoriously slow, and passed the hobby project you quickly
realize that.&lt;/p&gt;

&lt;p&gt;Python has a Global Interpreter Lock.&lt;/p&gt;

&lt;p&gt;SBCL compiles to machine code and is garbage collected [1].&lt;/p&gt;

&lt;p&gt;We can fine-tune the types in our Lisp programs for the compiler to
make the consequent optimizations. We can run in &amp;ldquo;debugging first&amp;rdquo; or
in &amp;ldquo;speed first&amp;rdquo; modes. We can inline code to gain in the cost of
function calls.&lt;/p&gt;

&lt;p&gt;As a consequence, you may not need memcached in your Lisp project yet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/performance.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/performance.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1udu69/how_to_make_lisp_go_faster_than_cpdf/&#34;&gt;CL can be tuned to be faster than C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;interesting stuff:
&lt;a href=&#34;https://github.com/marcoheisig/Petalisp&#34;&gt;Petalisp&lt;/a&gt; - an attempt to
generate high performance code for parallel computers by
JIT-compiling array definitions. It works on a more fundamental
level than NumPy, by providing even more powerful N-dimensional
arrays, but just a few building blocks for working on them.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tapoueh.org/blog/2014/05/why-is-pgloader-so-much-faster/&#34;&gt;pgloader&lt;/a&gt; was re-written from Python to Common Lisp for a 30x speed gain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[1]: and rest assured, &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/yes-google-develops-common-lisp/&#34;&gt;Google improves the GC&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;I hope I killed some FUD and showed you new ways to make stuff. May
that inspire you!&lt;/p&gt;

&lt;h1 id=&#34;appendix-faq&#34;&gt;Appendix: FAQ&lt;/h1&gt;

&lt;p&gt;Some info every Python programmer will come across eventually. Saves you some googling.&lt;/p&gt;

&lt;h2 id=&#34;are-there-no-iterators&#34;&gt;Are there no iterators ?&lt;/h2&gt;

&lt;p&gt;In practice, we mostly rely on closures, but there are libraries to
create iterators.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&#34;https://stackoverflow.com/questions/32956033/is-there-a-straightforward-lisp-equivalent-of-pythons-generators&#34;&gt;https://stackoverflow.com/questions/32956033/is-there-a-straightforward-lisp-equivalent-of-pythons-generators&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;can-i-define-my-own-operator-like-in-an-oo-language&#34;&gt;Can I define my own &lt;code&gt;+&lt;/code&gt; operator like in an OO language ?&lt;/h2&gt;

&lt;p&gt;By default, no, because the Common Lisp Object System (CLOS) came after the language specification
and thus everything isn&amp;rsquo;t object-based. However there are libraries
like &lt;a href=&#34;https://github.com/alex-gutev/generic-cl/&#34;&gt;generic-cl&lt;/a&gt; and, in
practice, we quickly forget about this. Different operators is also a
means for performance, good type inference and error messages.&lt;/p&gt;

&lt;h2 id=&#34;to-which-extent-can-lisp-be-compiled-with-all-its-dynamic-nature-garbage-collection-macros-and-what-else&#34;&gt;To which extent can Lisp be compiled, with all its dynamic nature, garbage collection, macros and what else ?&lt;/h2&gt;

&lt;p&gt;Many Lisp compilers compile to machine code (SBCL, CCL, CMUCL,…).&lt;/p&gt;

&lt;p&gt;Full answer: &lt;a href=&#34;https://stackoverflow.com/questions/913671/are-there-lisp-native-code-compilers/914383#914383&#34;&gt;https://stackoverflow.com/questions/913671/are-there-lisp-native-code-compilers/914383#914383&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;but-what-is-common-lisp-good-for-really&#34;&gt;But what is Common Lisp good for, really ?&lt;/h2&gt;

&lt;p&gt;We have a ready-to-use citation :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please don&amp;rsquo;t assume Lisp is only useful for Animation and Graphics, AI, Bio-informatics, B2B and Ecommerce, Data Mining, EDA/Semiconductor applications, Expert Systems, Finance, Intelligent Agents, Knowledge Management, Mechanical CAD, Modeling and Simulation, Natural Language, Optimization, Research, Risk Analysis, Scheduling, Telecom, and Web Authoring just because these are the only things they happened to list. &amp;ndash; Kent Pitman&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kent Pitman&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://www.nhplace.com/kent/quoted.html&#34;&gt;http://www.nhplace.com/kent/quoted.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See also &lt;a href=&#34;http://random-state.net/features-of-common-lisp.html&#34;&gt;http://random-state.net/features-of-common-lisp.html&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;so-why-is-cl-not-more-popular&#34;&gt;So why is CL not more popular ?&lt;/h2&gt;

&lt;p&gt;First, some reminders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;popularity doesn&amp;rsquo;t equal quality, and popularity is hard to
measure.&lt;/li&gt;
&lt;li&gt;some success stories: &lt;a href=&#34;http://lisp-lang.org/success/&#34;&gt;http://lisp-lang.org/success/&lt;/a&gt; Aircraft analysis suits, Missile defense, ICAD, music composition, algebra systems, bulk importer for PostgreSQL, grammar checking, 3D editor, knowledge graphs,…&lt;/li&gt;
&lt;li&gt;did you know that &lt;a href=&#34;https://tapoueh.org/blog/2014/05/why-is-pgloader-so-much-faster/&#34;&gt;pgloader&lt;/a&gt; was re-written from Python to Common Lisp? (for a x30 speed gain, among other benefits)&lt;/li&gt;
&lt;li&gt;CL was &lt;a href=&#34;https://www.youtube.com/watch?v=_gZK0tW8EhQ&amp;amp;feature=youtu.be&amp;amp;t=4175&#34;&gt;used in a spacecraft&lt;/a&gt; (and the REPL was used to debug the system live from the earth)&lt;/li&gt;
&lt;li&gt;some companies still use and pick CL: &lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies&#34;&gt;https://github.com/azzamsa/awesome-lisp-companies&lt;/a&gt;, companies provide professional support (&lt;a href=&#34;https://platform.sh/&#34;&gt;Platform.sh&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Google&amp;rsquo;s &lt;a href=&#34;https://en.wikipedia.org/wiki/ITA_Software&#34;&gt;ITA Software&lt;/a&gt; still powers airfare search on Orbitz or Kaya.com,&lt;/li&gt;
&lt;li&gt;reddit v1 was written in CL! JavaScript was &lt;del&gt;written&lt;/del&gt; sketched in CL! (&lt;a href=&#34;https://jorgetavares.com/2010/05/19/original-implementation-of-javascript-in-cl/&#34;&gt;see here&lt;/a&gt;, with lisp code still visible in the repository: &lt;a href=&#34;https://dxr.mozilla.org/mozilla/source/js2/semantics/&#34;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;CL was number 2 on the Tiobe index for years in the 80s!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That being said, my 2 cents since you ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I think the CL world missed the web bandwagon for some time (&lt;a href=&#34;http://common-lisp.net/&#34;&gt;common-lisp.net&lt;/a&gt; was horrible for some years), but that&amp;rsquo;s been fixed.&lt;/li&gt;
&lt;li&gt;an enormous code-base existed before GitHub.&lt;/li&gt;
&lt;li&gt;we missed visually nice, practical content on the web, even though
there are many books. It&amp;rsquo;s a bit better now.&lt;/li&gt;
&lt;li&gt;CL missed a package manager for some time behind other languages, that&amp;rsquo;s now fixed.&lt;/li&gt;
&lt;li&gt;I reckon CL is still quite hard for the web, it doesn&amp;rsquo;t have a killer web framework (though maybe &lt;a href=&#34;http://40ants.com/weblocks/quickstart.html&#34;&gt;Weblocks&lt;/a&gt;, &lt;a href=&#34;https://github.com/rabbibotton/clog&#34;&gt;CLOG&lt;/a&gt; or &lt;a href=&#34;https://github.com/interactive-ssr/hunchenissr&#34;&gt;ISSR&lt;/a&gt; soon©, all isomorphic web frameworks), hence no hype.&lt;/li&gt;
&lt;li&gt;CL seems to be used for big, non-trivial projects, hence it gets no easy hype.&lt;/li&gt;
&lt;li&gt;CL has no entity doing marketing today. We saw the Common Lisp
foundation pairing with sponsors recently. It &lt;em&gt;did&lt;/em&gt; receive a lot of
financial and institutional support from the MIT, the NASA, Xerox, Carnegie
Mellon University (CMUCL), Lisp vendors (Symbolics, Lucid, Franz…),…&lt;/li&gt;
&lt;li&gt;CL worked well with Emacs, Vim, CCL&amp;rsquo;s built-in editor on macOs,
LispWorks&amp;rsquo; editor (which has a free version), but this doesn&amp;rsquo;t
satisfy the masses. We now have more options, including Atom (very
good support), VSCode (okay support) and Eclipse (basic support).&lt;/li&gt;
&lt;li&gt;other reasons: it may be hard (or harder than the concurrence) to
grasp and getting started with, Lisp isn&amp;rsquo;t for everyone, it gets a lot of
FUD, and has a so-called Lisp curse!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;but that&amp;rsquo;s all debatable, I wouldn&amp;rsquo;t focus much on this. &lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-years-in-common-lisp-2018/#implementations&#34;&gt;Times are
good for
implementations&lt;/a&gt;, that&amp;rsquo;s what counts.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;how-do-i-get-started&#34;&gt;How do I get started?&lt;/h2&gt;

&lt;p&gt;You need to install &lt;code&gt;sbcl&lt;/code&gt; and run it in your terminal. From there you
can write code in the basic REPL (use &lt;code&gt;rlwrap sbcl&lt;/code&gt; for a readline
wrapper). You can write code to a file and use &lt;code&gt;(load &amp;quot;myfile.lisp&amp;quot;)&lt;/code&gt;
to load and execute it. Then you&amp;rsquo;ll want to install Quicklisp and to
set up a true editor. Here&amp;rsquo;s a video to get you started in no speed:&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/XFc513MJjos&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;However, make you a favor and learn some Lisp for good! I am creating
a video course on the Udemy platform, where I teach the language for
practical purposes, and where I make you avoid all the gotchas that I
faced during my journey.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s here: &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?couponCode=LISP4SUMMER2022&#34;&gt;Common Lisp Programming, from novice to effective programmer&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Replic v0.12</title>
      <link>/blog/replic-v0.12-readline-applications-with-custom-completion/</link>
      <pubDate>Tue, 29 Oct 2019 18:40:07 +0100</pubDate>
      
      <guid>/blog/replic-v0.12-readline-applications-with-custom-completion/</guid>
      <description>&lt;p&gt;We recently pushed our &lt;a href=&#34;https://github.com/vindarel/replic/&#34;&gt;replic&lt;/a&gt;
library version 0.12, adding a couple of expected features, thanks to
the input of our &lt;del&gt;users&lt;/del&gt; user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we can TAB-complete sentences (strings inside quotes)&lt;/li&gt;
&lt;li&gt;we can define a different completion method for each arguments of a
command.&lt;/li&gt;
&lt;li&gt;we added a declarative way to automatically print a function&amp;rsquo;s
result. The default function can be overriden by users (in order
too, for example, color output).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we can do something like this: we create a function (that will
become a command on the readline command line):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun say (verb name)
  (format t &amp;quot;~a, ~a !~&amp;amp;&amp;quot; verb name))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We define how to TAB-complete its arguments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(replic.completion:add-completion &amp;quot;say&amp;quot;
                                  (list &amp;quot;greetings&amp;quot; &amp;quot;\&amp;quot;nice to see you\&amp;quot;&amp;quot;)
                                  (lambda () *names*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if you type &lt;code&gt;say TAB&lt;/code&gt; you get the two greeting choices. After you
pick one and press TAB again, you get the names that were given to
&lt;code&gt;hello&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What&amp;rsquo;s beginning to be wanted now is fuzzy completion.&lt;/p&gt;

&lt;p&gt;Hope you enjoy.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;What is replic&amp;rsquo;s goal ?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Building a readline application is cool, but readline gives you the
basics and you must still build a REPL around it: loop and read
commands, catch a =C-c=, a =C-d=, ask confirmation to quit, print
the general help, the help of a command, setup the completion of
commands, the completion of their arguments, load an init file,
colorize output,&amp;hellip;  =replic= does this for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Replic&amp;rsquo;s goal is that when you have a lisp library, with lisp
functions, it should be straightforward to create a terminal
application out of it.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s an example in the wild. The &lt;code&gt;lyrics&lt;/code&gt; library is cool. It is a lisp library, it must be used on the Lisp REPL. This is the amount of code that was needed to create a terminal application out of it: &lt;a href=&#34;https://github.com/mihaiolteanu/lyrics/pull/1/files&#34;&gt;https://github.com/mihaiolteanu/lyrics/pull/1/files&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Compile Time Type Checking in Common Lisp</title>
      <link>/blog/compile-time-type-checking-in-common-lisp/</link>
      <pubDate>Tue, 29 Oct 2019 17:12:33 +0100</pubDate>
      
      <guid>/blog/compile-time-type-checking-in-common-lisp/</guid>
      <description>

&lt;p&gt;We often hear that Common Lisp is dynamically typed, which is not
wrong, but that leads to the belief that Lisp is as bad as Python
concerning types, which is plainly wrong. We don&amp;rsquo;t hear enough that CL
is a compiled language, that we can add type annotations, and that
SBCL does thorough type checking. Hence, what we have at hand is
awesome: we can compile a whole program or &lt;em&gt;compile a single function&lt;/em&gt;
and get type warnings. Once again, the feedback is immediate. We can
define our own types and get compile-time type warnings.&lt;/p&gt;

&lt;p&gt;You use a paramater that must be a list of list of strings of length 3
? Ok, define the type:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun list-of-3tuples-strings-p (list)
  &amp;quot;Return t if LIST is a list composed of 3-tuples, made only of strings.&amp;quot;
  (and (consp list)
       (every (lambda (it)
                (and
                 (= 3 (length it))
                 (every #&#39;stringp it)))
              list)))

(deftype alist-of-3tuples-strings ()
  `(satisfies list-of-3tuples-strings-p))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and type the variable as explained below.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s useful for development, it&amp;rsquo;s also great to catch errors in a
user&amp;rsquo;s configuration file. Checks are done when we &lt;code&gt;load&lt;/code&gt; a file, and
error messages are explicit. We use this now in the Next browser.&lt;/p&gt;

&lt;p&gt;We don&amp;rsquo;t hear a lot about all that, maybe because the information was
hard to find, maybe because SBCL was not there at the time Lisp books
were written. The following was published to the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/type.html&#34;&gt;Common Lisp
Cookbook /type.html&lt;/a&gt;, so
hopefully the issue is solved!&lt;/p&gt;

&lt;p&gt;On the topic, don&amp;rsquo;t miss these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the article &lt;a href=&#34;https://medium.com/@MartinCracauer/static-type-checking-in-the-programmable-programming-language-lisp-79bb79eb068a&#34;&gt;Static type checking in SBCL&lt;/a&gt;, by Martin Cracauer&lt;/li&gt;
&lt;li&gt;the article &lt;a href=&#34;https://alhassy.github.io/TypedLisp/&#34;&gt;Typed List, a Primer&lt;/a&gt; - let&amp;rsquo;s explore Lisp&amp;rsquo;s fine-grained type hierarchy! with a shallow comparison to Haskell.&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/stylewarning/coalton&#34;&gt;Coalton&lt;/a&gt; library
(pre-alpha): adding Hindley-Milner type checking to Common Lisp
which allows for gradual adoption, in the same way Typed Racket or
Hack allows for. It is as an embedded DSL in Lisp that resembles
Standard ML or OCaml, but lets you seamlessly interoperate with
non-statically-typed Lisp code (and vice versa).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;compile-time-type-checking&#34;&gt;Compile-time type checking&lt;/h2&gt;

&lt;p&gt;You may provide type information for variables, function arguments
etc via the macros &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/s_declar.htm&#34;&gt;&lt;code&gt;declare&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://www.xach.com/clhs?q=declaim&#34;&gt;&lt;code&gt;declaim&lt;/code&gt;&lt;/a&gt;.
However, similar to the &lt;code&gt;:type&lt;/code&gt; slot
introduced in &lt;a href=&#34;clos.html&#34;&gt;CLOS section&lt;/a&gt;, the effects of type declarations are
undefined in Lisp standard and are implementation specific. So there is no
guarantee that the Lisp compiler will perform compile-time type checking.&lt;/p&gt;

&lt;p&gt;However, it is possible, and SBCL is an implementation that does
thorough type checking.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s recall first that Lisp already warns about simple type
warnings. The following function wrongly wants to concatenate a string
and a number. When we compile it, we get a type warning.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defconstant +foo+ 3)
(defun bar ()
  (concatenate &#39;string &amp;quot;+&amp;quot; +foo+))
; caught WARNING:
;   Constant 3 conflicts with its asserted type SEQUENCE.
;   See also:
;     The SBCL Manual, Node &amp;quot;Handling of Types&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The example is simple, but it already shows a capacity some other
languages don&amp;rsquo;t have, and it is actually useful during development ;)
Now, we&amp;rsquo;ll do better.&lt;/p&gt;

&lt;h3 id=&#34;declaring-the-type-of-variables&#34;&gt;Declaring the type of variables&lt;/h3&gt;

&lt;p&gt;Use the macro &lt;a href=&#34;https://www.xach.com/clhs?q=declaim&#34;&gt;&lt;code&gt;declaim&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s declare that our global variable &lt;code&gt;*name*&lt;/code&gt; is a string (you can
type the following in any order in the REPL):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(declaim (type (string) *name*))
(defparameter *name* &amp;quot;book&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if we try to set it with a bad type, we get a &lt;code&gt;simple-type-error&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf *name* :me)
Value of :ME in (THE STRING :ME) is :ME, not a STRING.
   [Condition of type SIMPLE-TYPE-ERROR]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can do the same with our custom types. Let&amp;rsquo;s quickly declare the type &lt;code&gt;list-of-strings&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun list-of-strings-p (list)
  &amp;quot;Return t if LIST is non nil and contains only strings.&amp;quot;
  (and (consp list)
       (every #&#39;stringp list)))

(deftype list-of-strings ()
  `(satisfies list-of-strings-p))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let&amp;rsquo;s declare that our &lt;code&gt;*all-names*&lt;/code&gt; variables is a list of strings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(declaim (type (list-of-strings) *all-names*))
(defparameter *all-names* &amp;quot;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can compose types:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(declaim (type (or null list-of-strings) *all-names*))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;declaring-the-input-and-output-types-of-functions&#34;&gt;Declaring the input and output types of functions&lt;/h3&gt;

&lt;p&gt;We use again the &lt;code&gt;declaim&lt;/code&gt; macro, with &lt;code&gt;ftype (function …)&lt;/code&gt; instead of just &lt;code&gt;type&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(declaim (ftype (function (fixnum) fixnum) add))
;;                         ^^input ^^output [optional]
(defun add (n)
	(+ n  1))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With this we get nice type warnings at compile time.&lt;/p&gt;

&lt;p&gt;If we change the function to erroneously return a string instead of a
fixnum, we get a warning:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun add (n)
	(format nil &amp;quot;~a&amp;quot; (+ n  1)))
; caught WARNING:
;   Derived type of ((GET-OUTPUT-STREAM-STRING STREAM)) is
;     (VALUES SIMPLE-STRING &amp;amp;OPTIONAL),
;   conflicting with the declared function return type
;     (VALUES FIXNUM &amp;amp;REST T).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we use &lt;code&gt;add&lt;/code&gt; inside another function, to a place that expects a
string, we get a warning:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun bad-concat (n)
    (concatenate &#39;string (add n)))
; caught WARNING:
;   Derived type of (ADD N) is
;     (VALUES FIXNUM &amp;amp;REST T),
;   conflicting with its asserted type
;     SEQUENCE.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we use &lt;code&gt;add&lt;/code&gt; inside another function, and that function declares
its argument types which appear to be incompatible with those of
&lt;code&gt;add&lt;/code&gt;, we get a warning:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(declaim (ftype (function (string)) bad-arg))
(defun bad-arg (n)
    (add n))
; caught WARNING:
;   Derived type of N is
;     (VALUES STRING &amp;amp;OPTIONAL),
;   conflicting with its asserted type
;     FIXNUM.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This all happens indeed &lt;em&gt;at compile time&lt;/em&gt;, either in the REPL,
either with a simple &lt;code&gt;C-c C-c&lt;/code&gt; in Slime, or when we &lt;code&gt;load&lt;/code&gt; a file.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Reddit: ABCL Common Lisp vs Clojure</title>
      <link>/blog/reddit-abcl-common-lisp-vs-clojure/</link>
      <pubDate>Mon, 23 Sep 2019 01:47:10 +0200</pubDate>
      
      <guid>/blog/reddit-abcl-common-lisp-vs-clojure/</guid>
      <description>&lt;p&gt;Not that I&amp;rsquo;m interested in using the Java platform :D but relevant
comparisons between ABCL (Common Lisp on Java) and Clojure are
rare. We just had a nice feedback on reddit, so here it is. The
question was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After looking at the quite old benchmarks, ABCL seems to perform alright. Can anyone share their experience with ABCL in terms of performance, stability and memory usage?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;p&gt;I wish I could give you more concrete numbers with an application you could test and see for yourself. Since I can&amp;rsquo;t do that, I will tell you about my recent work with ABCL. I ported a small Clojure server-side utility to ABCL and can qualitatively tell you that the performance was close to Clojure. After profiling the ABCL version, I believe I can attribute the differences to ABCL&amp;rsquo;s use of Java reflection for its Java FFI.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve already been successfully deploying Clojure-based applications professionally, and as I&amp;rsquo;ve gotten more into Common Lisp, I&amp;rsquo;d like to start deploying Common Lisp based applications as well. I recently posted a patch to the ABCL mailing list and got a very quick response from the maintainer. I really like the quality of the ABCL code base. The compiler itself was very approachable and easy to understand.&lt;/p&gt;

&lt;p&gt;I think ABCL really is a worthwhile target in the Common Lisp world because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Painless Java FFI. You avoid all the instability and signaling issues that crop up when using the JVM combined with SBCL or CCL. If you make a lot of calls, native Java is always going to be faster anyhow than calls over JNI (which is more comparable to reflection).&lt;/li&gt;
&lt;li&gt;Use large heaps without worry. Part of the benefit of the JVM is its proven ability to have huge heaps (I&amp;rsquo;ve been part of projects that had 64GB+ heaps (though honestly I&amp;rsquo;d rather stay small)).&lt;/li&gt;
&lt;li&gt;JVM platform is well supported and tested on a number of OS and hardware platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SBCL uses conservative garbage collection and I&amp;rsquo;m curious how well it would handle really large heaps. CCL uses precise garbage collection but again, I&amp;rsquo;d like to know how it handles really large heaps. In general, I want all my applications to run with heaps that are naturally in CCL&amp;rsquo;s or SBCL&amp;rsquo;s sweet spot, but I&amp;rsquo;d love to know I could use ABCL if I really ever needed huge heaps. I&amp;rsquo;m really getting into Common Lisp because I really like the implementation choices. Having a solid Java FFI unfortunately is usually a requirement in my workplace.&lt;/p&gt;

&lt;p&gt;To me, ABCL will be /better/ than using Clojure if ABCL&amp;rsquo;s Java FFI moves away from reflection (when possible). This will close any performance gap with Clojure for most applications. I think this can be done relatively easily in the current ABCL implementation, and I have an idea of how to do it but unfortunately have had no time lately to devote to it. The reason I say &amp;ldquo;better than Clojure&amp;rdquo; is that I can write applications that target both ABCL and SBCL/CCL &amp;ndash; I can abstract away my Java APIs if I really have to have them (or use LispWorks with a solid Java FFI if I don&amp;rsquo;t need a ton of Java interoperability). Then when I need fast startup time or low memory footprint, I can use these other CL implementations which are much better suited to it.&lt;/p&gt;

&lt;p&gt;The main benefit where I still see Clojure having an edge is if you need a heavy JS-based web interface. I&amp;rsquo;m not a JS developer, but I was able to successfully use Clojurescript and make a nice looking web application that had pretty seamless interoperability with my Clojure-based server.&lt;/p&gt;

&lt;p&gt;Anyhow, I hope this helps you. ABCL is great, I have been very impressed with it and I encourage you to try it out.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;by the user &lt;code&gt;somewhat-functional&lt;/code&gt; &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/d48gcr/how_well_does_abcl_perform/&#34;&gt;on reddit&lt;/a&gt;, september 2019&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Slime Tips</title>
      <link>/blog/slime-tips/</link>
      <pubDate>Mon, 26 Aug 2019 10:40:46 +0200</pubDate>
      
      <guid>/blog/slime-tips/</guid>
      <description>

&lt;p&gt;Recently on reddit there was a reminder about
&lt;a href=&#34;https://lisptips.com/&#34;&gt;lisptips.com&lt;/a&gt; and
&lt;a href=&#34;https://slime-tips.tumblr.com/&#34;&gt;slime-tips&lt;/a&gt;. I already knew the two,
but this time I fully enjoyed the Slime tips. I copy my favourites.&lt;/p&gt;

&lt;p&gt;As usual, I enhanced the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/emacs-ide.html&#34;&gt;Cookbook/emacs-ide.html&lt;/a&gt; at the same time.&lt;/p&gt;

&lt;p&gt;The Slime documentation is here: &lt;a href=&#34;https://common-lisp.net/project/slime/doc/html/&#34;&gt;https://common-lisp.net/project/slime/doc/html/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;documentation-lookup&#34;&gt;Documentation lookup&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;C-c C-d h&lt;/strong&gt;  looks up documentation in CLHS. But it works only on symbols, so there are two more bindings:&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-d #&lt;/strong&gt; for reader macros&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-d ~&lt;/strong&gt;  for format directives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other bindings which may be useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;C-c C-d d&lt;/strong&gt;  describes a symbol using &lt;code&gt;describe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-d f&lt;/strong&gt;  describes a function using &lt;code&gt;describe&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;synchronizing-packages&#34;&gt;Synchronizing packages&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;C-c ~&lt;/strong&gt; (&lt;em&gt;slime-sync-package-and-default-directory&lt;/em&gt;): When run in a
buffer with a lisp file it will change the current package of the REPL
to the package of that file and also set the current directory of the REPL
to the parent directory of the file.&lt;/p&gt;

&lt;h2 id=&#34;calling-code&#34;&gt;Calling code&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;C-c C-y&lt;/strong&gt; (&lt;em&gt;slime-call-defun&lt;/em&gt;): When the point is inside a defun and
C-c C-y is pressed,&lt;/p&gt;

&lt;p&gt;(I’ll use [] as an indication where the cursor is)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun foo ()
 nil[])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then &lt;code&gt;(foo [])&lt;/code&gt; will be inserted into the REPL, so that you can write
additional arguments and run it.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;foo&lt;/code&gt; was in a different package than the package of the REPL,
&lt;code&gt;(package:foo )&lt;/code&gt; or &lt;code&gt;(package::foo )&lt;/code&gt; will be inserted.&lt;/p&gt;

&lt;p&gt;This feature is very useful for testing a function you just wrote.&lt;/p&gt;

&lt;p&gt;That works not only for defun, but also for defgeneric, defmethod,
defmacro, and define-compiler-macro in the same fashion as for defun.&lt;/p&gt;

&lt;p&gt;For defvar, defparameter, defconstant: &lt;code&gt;[] *foo*&lt;/code&gt; will be inserted
(the cursor is positioned before the symbol so that you can easily
wrap it into a function call).&lt;/p&gt;

&lt;p&gt;For defclass: &lt;code&gt;(make-instance ‘class-name )&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inserting calls to frames in the debugger&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-y&lt;/strong&gt; in SLDB on a frame will insert a call to that frame into the REPL, e.g.,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(/ 0) =&amp;gt;
…
1: (CCL::INTEGER-/-INTEGER 1 0)
…
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;C-y&lt;/strong&gt; will insert &lt;code&gt;(CCL::INTEGER-/-INTEGER 1 0)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(thanks to &lt;a href=&#34;https://slime-tips.tumblr.com/page/2&#34;&gt;Slime tips&lt;/a&gt;)&lt;/p&gt;

&lt;h2 id=&#34;exporting-symbols&#34;&gt;Exporting symbols&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;C-c x&lt;/strong&gt; (&lt;em&gt;slime-export-symbol-at-point&lt;/em&gt;) from the &lt;code&gt;slime-package-fu&lt;/code&gt;
contrib: takes the symbol at point and modifies the &lt;code&gt;:export&lt;/code&gt; clause of
the corresponding defpackage form. It also exports the symbol.  When
called with a negative argument (C-u C-c x) it will remove the symbol
from &lt;code&gt;:export&lt;/code&gt; and unexport it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;M-x slime-export-class&lt;/strong&gt; does the same but with symbols defined
by a structure or a class, like accesors, constructors, and so on.
It works on structures only on SBCL and Clozure CL so far.
Classes should work everywhere with MOP.&lt;/p&gt;

&lt;p&gt;Customization&lt;/p&gt;

&lt;p&gt;There are different styles of how symbols are presented in
&lt;code&gt;defpackage&lt;/code&gt;, the default is to use uninterned symbols (&lt;code&gt;#:foo&lt;/code&gt;).
This can be changed:&lt;/p&gt;

&lt;p&gt;to use keywords:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setq slime-export-symbol-representation-function
      (lambda (n) (format &amp;quot;:%s&amp;quot; n)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or strings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setq slime-export-symbol-representation-function
 (lambda (n) (format &amp;quot;\&amp;quot;%s\&amp;quot;&amp;quot; (upcase n))))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;crossreferencing-find-who-s-calling-referencing-setting-a-symbol&#34;&gt;Crossreferencing: find who&amp;rsquo;s calling, referencing, setting a symbol&lt;/h3&gt;

&lt;p&gt;Slime has a nice cross referencing facility, for example, you can see
what calls a particular function or expands a macro.  It presents a
list of places which reference a particular entity, from there you can
recompile the thing which references by pressing &lt;strong&gt;C-c C-c&lt;/strong&gt; on that
line. &lt;strong&gt;C-c C-k&lt;/strong&gt; will recompile all the references. This is useful when
modifying macros, inline functions, or constants.&lt;/p&gt;

&lt;p&gt;The following bindings are also shown in Slime&amp;rsquo;s menu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;C-c C-w c&lt;/strong&gt; &lt;em&gt;slime-who-calls&lt;/em&gt; callers of a function&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-w m&lt;/strong&gt; &lt;em&gt;slime-who-macroexpands&lt;/em&gt; places where a macro is expanded&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-w r&lt;/strong&gt; &lt;em&gt;slime-who-references&lt;/em&gt; global variable references&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-w b&lt;/strong&gt; &lt;em&gt;slime-who-bind&lt;/em&gt; global variable bindings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-w s&lt;/strong&gt; &lt;em&gt;slime-who-sets&lt;/em&gt; global variable setters&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C-c C-w a&lt;/strong&gt; &lt;em&gt;slime-who-specializes&lt;/em&gt; methods specialized on a symbol&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when the &lt;code&gt;slime-asdf&lt;/code&gt; contrib is enabled,
&lt;strong&gt;C-c C-w d&lt;/strong&gt; &lt;em&gt;slime-who-depends-on&lt;/em&gt; lists dependent ASDF systems&lt;/p&gt;

&lt;p&gt;And a general binding: &lt;strong&gt;M-? or M-_&lt;/strong&gt; *slime-edit-uses** combines all
of the above, it lists every kind of references.&lt;/p&gt;

&lt;h2 id=&#34;monitoring-and-controlling-threads-with-slime&#34;&gt;Monitoring and controlling threads with Slime&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;M-x slime-list-threads&lt;/strong&gt; (you can also access it through the
&lt;em&gt;slime-selector&lt;/em&gt;, shortcut &lt;strong&gt;t&lt;/strong&gt;) will list running threads by their
names, and their statuses.&lt;/p&gt;

&lt;p&gt;The thread on the current line can be killed with &lt;strong&gt;k&lt;/strong&gt;, or if there’s a
lot of threads to kill, several lines can be selected and &lt;strong&gt;k&lt;/strong&gt; will kill
all the threads in the selected region.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;g&lt;/strong&gt; will update the thread list, but when you have a lot of threads
starting and stopping it may be too cumbersome to always press &lt;strong&gt;g&lt;/strong&gt;, so
there’s a variable &lt;code&gt;slime-threads-update-interval&lt;/code&gt;, when set to a number
X the thread list will be automatically updated each X seconds, a
reasonable value would be 0.5.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to Check Slots Types at make-instance</title>
      <link>/blog/how-to-check-slots-types-at-make-instance/</link>
      <pubDate>Wed, 10 Jul 2019 15:28:08 +0200</pubDate>
      
      <guid>/blog/how-to-check-slots-types-at-make-instance/</guid>
      <description>&lt;p&gt;In CLOS, a slot can have a &lt;code&gt;:type&lt;/code&gt; option, but it doesn&amp;rsquo;t inforce type
checking. It is good practice to use it, for documentation and for
compiler optimizations and warnings sometimes (with CCL and SBCL when
safety is high), but one shouldn&amp;rsquo;t rely on it. To comply this need, we
can simply create our own constructor functions.&lt;/p&gt;

&lt;p&gt;However, the
&lt;a href=&#34;https://github.com/fisxoj/sanity-clause&#34;&gt;sanity-clause&lt;/a&gt; library can
do it since a couple of days. The validation error messages are
pretty good.  Demonstration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sanity clause is a data validation/contract library. You might use it for configuration data, validating an api response, or documents from a datastore. In a dynamically typed langauge, it helps you define clearly defined areas of doubt and uncertainty. We should love our users, but we should never blindly trust their inputs.&lt;/p&gt;

&lt;p&gt;To make use of it, you define schemas, which can be property lists with symbols for keys and instances of :class:sanity-clause.field:field&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We define a class &lt;code&gt;person&lt;/code&gt; with slot options from sanity-clause:
&lt;code&gt;:field-type&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt; &lt;code&gt;:members&lt;/code&gt;, &lt;code&gt;:required&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((favorite-dog :type symbol
                 :field-type :member
                 :members (:wedge :walter)
                 :initarg :favorite-dog
                 :required t)
   (age :type (integer 0)
        :initarg :age
        :required t)
   (potato :type string
           :initarg :potato
           :required t))
  (:metaclass sanity-clause.metaclass:validated-metaclass))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we try to create a &lt;code&gt;person&lt;/code&gt; with &lt;code&gt;make-instance&lt;/code&gt;, but we give a bad dog name:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;person :favorite-dog :nope)
; Evaluation aborted on Error converting value for field #&amp;lt;MEMBER-FIELD {1004BFA973}&amp;gt;:
Value &amp;quot;NOPE&amp;quot; couldn&#39;t be found in set (WEDGE WALTER)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now with a bad age:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;person :age -1 :favorite-dog :walter)
; Evaluation aborted on Error validating value -1 in field #&amp;lt;INTEGER-FIELD {1004BFF103}&amp;gt;:
* Value -1 didn&#39;t satisfy condition &amp;quot;must be larger than 0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When a required field is missing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;person :age 7 :favorite-dog :walter)
; Evaluation aborted on A value for field POTATO is required but none was provided..
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And well, it works when all is OK :]&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;person :age 1 :favorite-dog :walter :potato &amp;quot;patate&amp;quot;)
#&amp;lt;PERSON {10060371E3}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The usual warnings apply: it&amp;rsquo;s a new library, we must try it and use
it with caution. It however opens up more possibilities. It would be
awesome to couple it with an ORM like Mito. This is an &lt;a href=&#34;https://github.com/fisxoj/sanity-clause/issues/8&#34;&gt;open
issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/51723992/how-to-force-slots-type-to-be-checked-during-make-instance/56920918&#34;&gt;https://stackoverflow.com/questions/51723992/how-to-force-slots-type-to-be-checked-during-make-instance/56920918&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html#slot-type&#34;&gt;https://lispcookbook.github.io/cl-cookbook/clos.html#slot-type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Web Development in Common Lisp: frameworks overview, templating, deployment</title>
      <link>/blog/web-development-in-common-lisp/</link>
      <pubDate>Mon, 08 Jul 2019 01:21:47 +0200</pubDate>
      
      <guid>/blog/web-development-in-common-lisp/</guid>
      <description>

&lt;p&gt;We just published a long overdue page on the Cookbook: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/web.html&#34;&gt;web
development in Common
Lisp&lt;/a&gt;. We have an
ambivalent feeling about it since it isn&amp;rsquo;t really a recipe as in the
other pages. Yet it is valuable content that required a certain amount
of digging and tryouts. Indeed, it took us about two years to discover
and advertise many projects, to learn, try and put a tutorial
together. We also wrote a commercial application. During that time, we
were taking notes on our &lt;a href=&#34;/web-dev/&#34;&gt;web-dev/&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;We present Hunchentoot, Clack (briefly), we have an overview of other
web frameworks, of templating libraries, we introduce Weblocks, we give
recipes for common tasks (such as checking if a user is logged in,
encrypting passwords), and we speak about deployment.&lt;/p&gt;

&lt;p&gt;Some topics still need to be adressed, so check for updates on the Cookbook !&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Prior notice:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some people sell ten pages long ebooks or publish their tutorial on
Gitbook to have a purchase option. I prefer to enhance the
collaborative Cookbook (I am by far &lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/graphs/contributors&#34;&gt;the main
contributor&lt;/a&gt;). You
can tip me on liberapay if you like:
&lt;a href=&#34;https://liberapay.com/vindarel/&#34;&gt;https://liberapay.com/vindarel/&lt;/a&gt;. Thanks !&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;For web development as for any other task, one can leverage Common
Lisp&amp;rsquo;s advantages: the unmatched REPL and exception handling system,
performance, the ability to build a self-contained executable,
stability, good threads story, strong typing, etc. We can, say, define
a new route and try it right away, there is no need to restart any
running server. We can change and compile &lt;em&gt;one function at a time&lt;/em&gt;
(the usual &lt;code&gt;C-c C-c&lt;/code&gt; in Slime) and try it. The feedback is
immediate. We can choose the degree of interactivity: the web server
can catch exceptions and fire the interactive debugger, or print lisp
backtraces on the browser, or display a 404 error page and print logs
on standard output. The ability to build self-contained executables eases
deployment tremendously (compared to, for example, npm-based apps), in
that we just copy the executable to a server and run it.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll present here some established web frameworks and other common
libraries to help you getting started in developing a web
application. We do &lt;em&gt;not&lt;/em&gt; aim to be exhaustive nor to replace the
upstream documentation. Your feedback and contributions are
appreciated.&lt;/p&gt;

&lt;!-- form creation, form validation --&gt;

&lt;!-- Javascript --&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#overview&#34;&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#installation&#34;&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#simple-webserver&#34;&gt;Simple webserver&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#serve-local-files&#34;&gt;Serve local files&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hunchentoot&#34;&gt;Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#access-your-server-from-the-internet&#34;&gt;Access your server from the internet&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hunchentoot-1&#34;&gt;Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#routing&#34;&gt;Routing&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#simple-routes&#34;&gt;Simple routes&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hunchentoot-2&#34;&gt;Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#caveman&#34;&gt;Caveman&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#accessing-get-and-post-parameters&#34;&gt;Accessing GET and POST parameters&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hunchentoot-3&#34;&gt;Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#error-handling&#34;&gt;Error handling&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hunchentoot-4&#34;&gt;Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#clack&#34;&gt;Clack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#weblocks---solving-the-javascript-problem&#34;&gt;Weblocks - solving the &amp;ldquo;JavaScript problem&amp;rdquo;©&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#templates&#34;&gt;Templates&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#djula---html-markup&#34;&gt;Djula - HTML markup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#spinneret---lispy-templates&#34;&gt;Spinneret - lispy templates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#connecting-to-a-database&#34;&gt;Connecting to a database&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#checking-a-user-is-logged-in&#34;&gt;Checking a user is logged-in&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#encrypting-passwords&#34;&gt;Encrypting passwords&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#building&#34;&gt;Building&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#building-a-self-contained-executable&#34;&gt;Building a self-contained executable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#continuous-delivery-with-travis-ci-or-gitlab-ci&#34;&gt;Continuous delivery with Travis CI or Gitlab CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#multiplatform-delivery-with-electron&#34;&gt;Multiplatform delivery with Electron&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deployment&#34;&gt;Deployment&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#deploying-manually&#34;&gt;Deploying manually&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#daemonizing-restarting-in-case-of-crashes-handling-logs-with-systemd&#34;&gt;Daemonizing, restarting in case of crashes, handling logs with Systemd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-docker&#34;&gt;With Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-guix&#34;&gt;With Guix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deploying-on-heroku-and-other-services&#34;&gt;Deploying on Heroku and other services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#monitoring&#34;&gt;Monitoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#connecting-to-a-remote-lisp-image&#34;&gt;Connecting to a remote Lisp image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hot-reload&#34;&gt;Hot reload&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#credits&#34;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;overview&#34;&gt;Overview&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://edicl.github.io/hunchentoot&#34;&gt;Hunchentoot&lt;/a&gt; and &lt;a href=&#34;https://github.com/fukamachi/clack&#34;&gt;Clack&lt;/a&gt; are two projects that
you&amp;rsquo;ll often hear about.&lt;/p&gt;

&lt;p&gt;Hunchentoot is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a web server and at the same time a toolkit for building dynamic websites. As a stand-alone web server, Hunchentoot is capable of HTTP/1.1 chunking (both directions), persistent connections (keep-alive), and SSL. It provides facilities like automatic session handling (with and without cookies), logging, customizable error handling, and easy access to GET and POST parameters sent by the client.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a software written by Edi Weitz (&amp;ldquo;Common Lisp Recipes&amp;rdquo;,
&lt;code&gt;cl-ppcre&lt;/code&gt; and &lt;a href=&#34;https://edicl.github.io/&#34;&gt;much more&lt;/a&gt;), it&amp;rsquo;s used and
proven solid. One can achieve a lot with it, but sometimes with more
friction than with a traditional web framework. For example,
dispatching a route by the HTTP method is a bit convoluted, one must
write a function for the &lt;code&gt;:uri&lt;/code&gt; parameter that does the check, when it
is a built-in keyword in other frameworks like Caveman.&lt;/p&gt;

&lt;p&gt;Clack is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a web application environment for Common Lisp inspired by Python&amp;rsquo;s WSGI and Ruby&amp;rsquo;s Rack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also written by a prolific lisper
(&lt;a href=&#34;https://github.com/fukamachi/&#34;&gt;E. Fukamachi&lt;/a&gt;), it actually uses
Hunchentoot by default as the server, but thanks to its pluggable
architecture one can use another web server, like the asynchronous
&lt;a href=&#34;https://github.com/fukamachi/woo&#34;&gt;Woo&lt;/a&gt;, built on the
&lt;a href=&#34;http://software.schmorp.de/pkg/libev.html&#34;&gt;libev&lt;/a&gt; event loop, maybe
&amp;ldquo;the fastest web server written in any programming language&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll cite also &lt;a href=&#34;https://github.com/orthecreedence/wookie&#34;&gt;Wookie&lt;/a&gt;, an asynchronous HTTP server, and its
companion library
&lt;a href=&#34;https://github.com/orthecreedence/cl-async&#34;&gt;cl-async&lt;/a&gt;, for general
purpose, non-blocking programming in Common Lisp, built on libuv, the
backend library in Node.js.&lt;/p&gt;

&lt;p&gt;Clack being more recent and less documented, and Hunchentoot a
de-facto standard, we&amp;rsquo;ll concentrate on the latter for this
recipe. Your contributions are of course welcome.&lt;/p&gt;

&lt;p&gt;Web frameworks build upon web servers and can provide facilities for
common activities in web development, like a templating system, access
to a database, session management, or facilities to build a REST api.&lt;/p&gt;

&lt;p&gt;Some web frameworks include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/caveman&#34;&gt;Caveman&lt;/a&gt;, by E. Fukamachi. It provides, out of the box,
database management, a templating engine (Djula), a project skeleton
generator, a routing system à la Flask or Sinatra, deployment options
(mod_lisp or FastCGI), support for Roswell on the command line, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shirakumo/radiance&#34;&gt;Radiance&lt;/a&gt;, by &lt;a href=&#34;https://github.com/Shinmera&#34;&gt;Shinmera&lt;/a&gt;
(Qtools, Portacle, lquery, …), is a web application environment,
more general than usual web frameworks. It lets us write and tie
websites and applications together, easing their deployment as a
whole. It has thorough &lt;a href=&#34;https://shirakumo.github.io/radiance/&#34;&gt;documentation&lt;/a&gt;, a &lt;a href=&#34;https://github.com/Shirakumo/radiance-tutorial&#34;&gt;tutorial&lt;/a&gt;, &lt;a href=&#34;https://github.com/Shirakumo/radiance-contribs&#34;&gt;modules&lt;/a&gt;, &lt;a href=&#34;https://github.com/Shirakumo?utf8=%E2%9C%93&amp;amp;q=radiance&amp;amp;type=&amp;amp;language=&#34;&gt;pre-written applications&lt;/a&gt; such as &lt;a href=&#34;https://github.com/Shirakumo/purplish&#34;&gt;an image board&lt;/a&gt; or a &lt;a href=&#34;https://github.com/Shirakumo/reader&#34;&gt;blogging platform&lt;/a&gt;, and more.
For example websites, see
&lt;a href=&#34;https://shinmera.com/&#34;&gt;https://shinmera.com/&lt;/a&gt;,
&lt;a href=&#34;https://reader.tymoon.eu/&#34;&gt;reader.tymoon.eu&lt;/a&gt; and &lt;a href=&#34;https://events.tymoon.eu/&#34;&gt;events.tymoon.eu&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/joaotavora/snooze&#34;&gt;Snooze&lt;/a&gt;, by João Távora (Sly, Emacs&amp;rsquo; Yasnippet, Eglot, …),
is &amp;ldquo;an URL router designed around REST web services&amp;rdquo;. It is
different because in Snooze, routes are just functions and HTTP
conditions are just Lisp conditions.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmontone/cl-rest-server&#34;&gt;cl-rest-server&lt;/a&gt; is a library for writing REST web
APIs. It features validation with schemas, annotations for logging,
caching, permissions or authentication, documentation via OpenAPI (Swagger),
etc.&lt;/li&gt;
&lt;li&gt;last but not least, &lt;a href=&#34;https://github.com/40ants/weblocks&#34;&gt;Weblocks&lt;/a&gt; is a venerable Common Lisp
web framework that permits to write ajax-based dynamic web
applications without writing any JavaScript, nor writing some lisp
that would transpile to JavaScript. It is seeing an extensive
rewrite and update since 2017. We present it in more details below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a full list of libraries for the web, please see the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#network-and-internet&#34;&gt;awesome-cl
list
#network-and-internet&lt;/a&gt;
and &lt;a href=&#34;https://www.cliki.net/Web&#34;&gt;Cliki&lt;/a&gt;. If you are looking for a
featureful static site generator, see
&lt;a href=&#34;https://github.com/coleslaw-org/coleslaw&#34;&gt;Coleslaw&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;installation&#34;&gt;Installation&lt;/h1&gt;

&lt;p&gt;Let&amp;rsquo;s install the libraries we&amp;rsquo;ll use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &#39;(&amp;quot;hunchentoot&amp;quot; &amp;quot;caveman&amp;quot; &amp;quot;spinneret&amp;quot; &amp;quot;djula&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To try Weblocks, please see its documentation. The Weblocks in
Quicklisp is not yet, as of writing, the one we are interested in.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll start by serving local files and we&amp;rsquo;ll run more than one local
server in the running image.&lt;/p&gt;

&lt;h1 id=&#34;simple-webserver&#34;&gt;Simple webserver&lt;/h1&gt;

&lt;h2 id=&#34;serve-local-files&#34;&gt;Serve local files&lt;/h2&gt;

&lt;h3 id=&#34;hunchentoot&#34;&gt;Hunchentoot&lt;/h3&gt;

&lt;p&gt;Create and start a webserver like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *acceptor* (make-instance &#39;hunchentoot:easy-acceptor :port 4242))
(hunchentoot:start *acceptor*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create an instance of &lt;code&gt;easy-acceptor&lt;/code&gt; on port 4242 and we start
it. We can now access &lt;a href=&#34;http://127.0.0.1:4242/&#34;&gt;http://127.0.0.1:4242/&lt;/a&gt;. You should get a welcome
screen with a link to the documentation and logs to the console.&lt;/p&gt;

&lt;p&gt;By default, Hunchentoot serves the files from the &lt;code&gt;www/&lt;/code&gt; directory in
its source tree. Thus, if you go to the source of
&lt;code&gt;easy-acceptor&lt;/code&gt; (&lt;code&gt;M-.&lt;/code&gt; in Slime), which is probably
&lt;code&gt;~/quicklisp/dists/quicklisp/software/hunchentoot-v1.2.38/&lt;/code&gt;, you&amp;rsquo;ll
find the &lt;code&gt;root/&lt;/code&gt; directory. It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an &lt;code&gt;errors/&lt;/code&gt; directory, with the error templates &lt;code&gt;404.html&lt;/code&gt; and &lt;code&gt;500.html&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;img/&lt;/code&gt; directory,&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;index.html&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To serve another directory, we give the option &lt;code&gt;document-root&lt;/code&gt; to
&lt;code&gt;easy-acceptor&lt;/code&gt;. We can also set the slot with its accessor:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (hunchentoot:acceptor-document-root *acceptor*) #p&amp;quot;path/to/www&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s create our &lt;code&gt;index.html&lt;/code&gt; first. Put this in a new
&lt;code&gt;www/index.html&lt;/code&gt; at the current directory (of the lisp repl):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Hello!&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello local server!&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;
    We just served our own files.
    &amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s start a new acceptor on a new port:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *my-acceptor* (make-instance &#39;hunchentoot:easy-acceptor :port 4444
                                   :document-root #p&amp;quot;www/&amp;quot;))
(hunchentoot:start *my-acceptor*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;go to &lt;a href=&#34;http://127.0.0.1:4444/&#34;&gt;p://127.0.0.1:4444/&lt;/a&gt; and see the difference.&lt;/p&gt;

&lt;p&gt;Note that we just created another &lt;em&gt;acceptor&lt;/em&gt; on a different port on
the same lisp image. This is already pretty cool.&lt;/p&gt;

&lt;h1 id=&#34;access-your-server-from-the-internet&#34;&gt;Access your server from the internet&lt;/h1&gt;

&lt;h2 id=&#34;hunchentoot-1&#34;&gt;Hunchentoot&lt;/h2&gt;

&lt;p&gt;With Hunchentoot we have nothing to do, we can see the server from the
internet right away.&lt;/p&gt;

&lt;p&gt;If you evaluate this on your VPS:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(hunchentoot:start (make-instance &#39;hunchentoot:easy-acceptor :port 4242))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see it right away on your server&amp;rsquo;s IP.&lt;/p&gt;

&lt;p&gt;Stop it with &lt;code&gt;(hunchentoot:stop *)&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&#34;routing&#34;&gt;Routing&lt;/h1&gt;

&lt;h2 id=&#34;simple-routes&#34;&gt;Simple routes&lt;/h2&gt;

&lt;h3 id=&#34;hunchentoot-2&#34;&gt;Hunchentoot&lt;/h3&gt;

&lt;p&gt;To bind an existing function to a route, we create a &amp;ldquo;prefix dispatch&amp;rdquo;
that we push onto the &lt;code&gt;*dispatch-table*&lt;/code&gt; list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello ()
   (format nil &amp;quot;Hello, it works!&amp;quot;))

(push
  (hunchentoot:create-prefix-dispatcher &amp;quot;/hello.html&amp;quot; #&#39;hello)
  hunchentoot:*dispatch-table*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To create a route with a regexp, we use &lt;code&gt;create-regex-dispatcher&lt;/code&gt;, where
the url-as-regexp can be a string, an s-expression or a cl-ppcre scanner.&lt;/p&gt;

&lt;p&gt;If you didn&amp;rsquo;t yet, create an acceptor and start the server:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *server* (make-instance &#39;hunchentoot:easy-acceptor :port 4242))
(hunchentoot:start *server*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and access it on [&lt;a href=&#34;http://localhost:4242/hello.html]http://localhost:4242/hello.html)&#34;&gt;http://localhost:4242/hello.html]http://localhost:4242/hello.html)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can see logs on the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;127.0.0.1 - [2018-10-27 23:50:09] &amp;quot;get / http/1.1&amp;quot; 200 393 &amp;quot;-&amp;quot; &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&amp;quot;
127.0.0.1 - [2018-10-27 23:50:10] &amp;quot;get /img/made-with-lisp-logo.jpg http/1.1&amp;quot; 200 12583 &amp;quot;http://localhost:4242/&amp;quot; &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&amp;quot;
127.0.0.1 - [2018-10-27 23:50:10] &amp;quot;get /favicon.ico http/1.1&amp;quot; 200 1406 &amp;quot;-&amp;quot; &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&amp;quot;
127.0.0.1 - [2018-10-27 23:50:19] &amp;quot;get /hello.html http/1.1&amp;quot; 200 20 &amp;quot;-&amp;quot; &amp;quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a href=&#34;https://edicl.github.io/hunchentoot/#define-easy-handler&#34;&gt;define-easy-handler&lt;/a&gt; allows to create a function and to bind it to an uri at once.&lt;/p&gt;

&lt;p&gt;Its form follows&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define-easy-handler (function-name :uri &amp;lt;uri&amp;gt; …) (lambda list parameters)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where &lt;code&gt;&amp;lt;uri&amp;gt;&lt;/code&gt; can be a string or a function.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hunchentoot:define-easy-handler (say-yo :uri &amp;quot;/yo&amp;quot;) (name)
  (setf (hunchentoot:content-type*) &amp;quot;text/plain&amp;quot;)
  (format nil &amp;quot;Hey~@[ ~A~]!&amp;quot; name))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Visit it at &lt;a href=&#34;http://localhost:4242/yo&#34;&gt;p://localhost:4242/yo&lt;/a&gt; and add parameters on the url:
&lt;a href=&#34;http://localhost:4242/yo?name=Alice&#34;&gt;http://localhost:4242/yo?name=Alice&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just a thought… we didn&amp;rsquo;t explicitely ask Hunchentoot to add this
route to our first acceptor of the port 4242. Let&amp;rsquo;s try another acceptor (see
previous section), on port 4444: &lt;a href=&#34;http://localhost:4444/yo?name=Bob&#34;&gt;http://localhost:4444/yo?name=Bob&lt;/a&gt; It
works too ! In fact, &lt;code&gt;define-easy-handler&lt;/code&gt; accepts an &lt;code&gt;acceptor-names&lt;/code&gt;
parameter:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;acceptor-names (which is evaluated) can be a list of symbols which means that the handler will only be returned by DISPATCH-EASY-HANDLERS in acceptors which have one of these names (see ACCEPTOR-NAME). acceptor-names can also be the symbol T which means that the handler will be returned by DISPATCH-EASY-HANDLERS in every acceptor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, &lt;code&gt;define-easy-handler&lt;/code&gt; has the following signature:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define-easy-handler (function-name &amp;amp;key uri acceptor-names default-request-type) (lambda list parameters)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It also has a &lt;code&gt;default-parameter-type&lt;/code&gt; which we&amp;rsquo;ll use in a minute to get url parameters.&lt;/p&gt;

&lt;p&gt;There are also keys to know for the lambda list. Please see the documentation.&lt;/p&gt;

&lt;h3 id=&#34;caveman&#34;&gt;Caveman&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;caveman&#34;&gt;Caveman&lt;/a&gt; provides two ways to
define a route: the &lt;code&gt;defroute&lt;/code&gt; macro and the &lt;code&gt;@route&lt;/code&gt; pythonic
&lt;em&gt;annotation&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute &amp;quot;/welcome&amp;quot; (&amp;amp;key (|name| &amp;quot;Guest&amp;quot;))
  (format nil &amp;quot;Welcome, ~A&amp;quot; |name|))

@route GET &amp;quot;/welcome&amp;quot;
(lambda (&amp;amp;key (|name| &amp;quot;Guest&amp;quot;))
  (format nil &amp;quot;Welcome, ~A&amp;quot; |name|))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A route with an url parameter (note &lt;code&gt;:name&lt;/code&gt; in the url):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute &amp;quot;/hello/:name&amp;quot; (&amp;amp;key name)
  (format nil &amp;quot;Hello, ~A&amp;quot; name))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is also possible to define &amp;ldquo;wildcards&amp;rdquo; parameters. It works with
the &lt;code&gt;splat&lt;/code&gt; key:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute &amp;quot;/say/*/to/*&amp;quot; (&amp;amp;key splat)
  ; matches /say/hello/to/world
  (format nil &amp;quot;~A&amp;quot; splat))
;=&amp;gt; (hello world)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We must enable regexps with &lt;code&gt;:regexp t&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute (&amp;quot;/hello/([\\w]+)&amp;quot; :regexp t) (&amp;amp;key captures)
  (format nil &amp;quot;Hello, ~A!&amp;quot; (first captures)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;accessing-get-and-post-parameters&#34;&gt;Accessing GET and POST parameters&lt;/h2&gt;

&lt;h3 id=&#34;hunchentoot-3&#34;&gt;Hunchentoot&lt;/h3&gt;

&lt;p&gt;First of all, note that we can access query parameters anytime with&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hunchentoot:parameter &amp;quot;my-param&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It acts on the default &lt;code&gt;*request*&lt;/code&gt; object which is passed to all handlers.&lt;/p&gt;

&lt;p&gt;There is also &lt;code&gt;get-paramater&lt;/code&gt; and &lt;code&gt;post-parameter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Earlier we saw some key parameters to &lt;code&gt;define-easy-handler&lt;/code&gt;. We now
introduce &lt;code&gt;default-parameter-type&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We defined the following handler:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hunchentoot:define-easy-handler (say-yo :uri &amp;quot;/yo&amp;quot;) (name)
  (setf (hunchentoot:content-type*) &amp;quot;text/plain&amp;quot;)
  (format nil &amp;quot;Hey~@[ ~A~]!&amp;quot; name))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The variable &lt;code&gt;name&lt;/code&gt; is a string by default. Let&amp;rsquo;s check it out:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hunchentoot:define-easy-handler (say-yo :uri &amp;quot;/yo&amp;quot;) (name)
  (setf (hunchentoot:content-type*) &amp;quot;text/plain&amp;quot;)
  (format nil &amp;quot;Hey~@[ ~A~] you are of type ~a&amp;quot; name (type-of name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Going to &lt;a href=&#34;http://localhost:4242/yo?name=Alice&#34;&gt;http://localhost:4242/yo?name=Alice&lt;/a&gt; returns&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Hey Alice you are of type (SIMPLE-ARRAY CHARACTER (5))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To automatically bind it to another type, we use &lt;code&gt;default-parameter-type&lt;/code&gt;. It can be
one of those simple types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#39;string&lt;/code&gt; (default),&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#39;integer&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#39;character&lt;/code&gt; (accepting strings of length 1 only, otherwise it is nil)&lt;/li&gt;
&lt;li&gt;or &lt;code&gt;&#39;boolean&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;or a compound list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#39;(:list &amp;lt;type&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#39;(:array &amp;lt;type&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#39;(:hash-table &amp;lt;type&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;where &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt; is a simple type.&lt;/p&gt;

&lt;!-- ## Sessions --&gt;

&lt;!-- todo ? --&gt;

&lt;!-- ## Cookies --&gt;

&lt;h1 id=&#34;error-handling&#34;&gt;Error handling&lt;/h1&gt;

&lt;p&gt;In all frameworks, we can choose the level of interactivity. The web
framework can return a 404 page and print output on the repl, it can
catch errors and invoke the interactive lisp debugger, or it can show
the lisp backtrace on the html page.&lt;/p&gt;

&lt;h2 id=&#34;hunchentoot-4&#34;&gt;Hunchentoot&lt;/h2&gt;

&lt;p&gt;The global variables to set are &lt;code&gt;*catch-errors-p*&lt;/code&gt;,
&lt;code&gt;*show-lisp-errors-p*&lt;/code&gt; and &lt;code&gt;*show-lisp-backtraces-p*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hunchentoot also defines condition classes.&lt;/p&gt;

&lt;p&gt;See the documentation: &lt;a href=&#34;https://edicl.github.io/hunchentoot/#conditions&#34;&gt;https://edicl.github.io/hunchentoot/#conditions&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;clack&#34;&gt;Clack&lt;/h2&gt;

&lt;p&gt;Clack users might make a good use of plugins, like the clack-errors middleware: &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#clack-plugins&#34;&gt;https://github.com/CodyReichert/awesome-cl#clack-plugins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://camo.githubusercontent.com/17dd6e0a7a916c8118f0134a94404f6757bee9dc/68747470733a2f2f7261772e6769746875622e636f6d2f6575646f786961302f636c61636b2d6572726f72732f6d61737465722f73637265656e73686f742d6465762e706e67&#34; width=&#34;800&#34;/&gt;&lt;/p&gt;

&lt;h1 id=&#34;weblocks-solving-the-javascript-problem&#34;&gt;Weblocks - solving the &amp;ldquo;JavaScript problem&amp;rdquo;©&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/40ants/weblocks&#34;&gt;Weblocks&lt;/a&gt; is a widgets-based and
server-based framework with a built-in ajax update mechanism. It
allows to write dynamic web applications &lt;em&gt;without the need to write
JavaScript or to write lisp code that would transpile to JavaScript&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://40ants.com/weblocks/_images/quickstart-check-task.gif&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Weblocks is an old framework developed by Slava Akhmechet, Stephen
Compall and Leslie Polzer. After nine calm years, it is seeing a very
active update, refactoring and rewrite effort by Alexander Artemenko.&lt;/p&gt;

&lt;p&gt;It was initially based on continuations (they were removed to date)
and thus a lispy cousin of Smalltalk&amp;rsquo;s
&lt;a href=&#34;https://en.wikipedia.org/wiki/Seaside_(software)&#34;&gt;Seaside&lt;/a&gt;. We can
also relate it to Haskell&amp;rsquo;s Haste, OCaml&amp;rsquo;s Eliom,
Elixir&amp;rsquo;s Phoenix LiveView and others.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;http://ultralisp.org/&#34;&gt;Ultralisp&lt;/a&gt; website is an example Weblocks
website in production known in the CL community.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Weblock&amp;rsquo;s unit of work is the &lt;em&gt;widget&lt;/em&gt;. They look like a class definition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defwidget task ()
        ((title
          :initarg :title
          :accessor title)
         (done
          :initarg :done
          :initform nil
          :accessor done)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then all we have to do is to define the &lt;code&gt;render&lt;/code&gt; method for this widget:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod render ((task task))
        &amp;quot;Render a task.&amp;quot;
        (with-html
              (:span (if (done task)
                         (with-html
                               (:s (title task)))
                       (title task)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It uses the Spinneret template engine by default, but we can bind any
other one of our choice.&lt;/p&gt;

&lt;p&gt;To trigger an ajax event, we write lambdas in full Common Lisp:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;...
(with-html
          (:p (:input :type &amp;quot;checkbox&amp;quot;
            :checked (done task)
            :onclick (make-js-action
                      (lambda (&amp;amp;key &amp;amp;allow-other-keys)
                        (toggle task))))
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The function &lt;code&gt;make-js-action&lt;/code&gt; creates a simple javascript function
that calls the lisp one on the server, and automatically refreshes the
HTML of the widgets that need it. In our example, it re-renders one
task only.&lt;/p&gt;

&lt;p&gt;Is it appealing ? Carry on this quickstart guide here: &lt;a href=&#34;http://40ants.com/weblocks/quickstart.html&#34;&gt;http://40ants.com/weblocks/quickstart.html&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;templates&#34;&gt;Templates&lt;/h1&gt;

&lt;h2 id=&#34;djula-html-markup&#34;&gt;Djula - HTML markup&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/mmontone/djula&#34;&gt;Djula&lt;/a&gt; is a port of Python&amp;rsquo;s
Django template engine to Common Lisp. It has &lt;a href=&#34;https://mmontone.github.io/djula/doc/build/html/index.html&#34;&gt;excellent documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Caveman uses it by default, but otherwise it is not difficult to
setup. We must declare where our templates are with something like&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(djula:add-template-directory (asdf:system-relative-pathname &amp;quot;webapp&amp;quot; &amp;quot;templates/&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A Djula template looks like this, no surprises (forgive the antislash
in &lt;code&gt;\%&lt;/code&gt;, this is a Jekyll limitation):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{\% extends &amp;quot;base.html&amp;quot; \%}
{\% block title %}Memberlist{\% endblock \%}
{\% block content \%}
  &amp;lt;ul&amp;gt;
  {\% for user in users \%}
    &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;{{ user.url }}&amp;quot;&amp;gt;{{ user.username }}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  {\% endfor \%}
  &amp;lt;/ul&amp;gt;
{\% endblock \%}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Djula compiles the templates before rendering them.&lt;/p&gt;

&lt;p&gt;It is, along with its companion
&lt;a href=&#34;https://github.com/AccelerationNet/access/&#34;&gt;access&lt;/a&gt; library, one of
the most downloaded libraries of Quicklisp.&lt;/p&gt;

&lt;h2 id=&#34;spinneret-lispy-templates&#34;&gt;Spinneret - lispy templates&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/ruricolist/spinneret&#34;&gt;Spinneret&lt;/a&gt; is a &amp;ldquo;lispy&amp;rdquo;
HTML5 generator. It looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-page (:title &amp;quot;Home page&amp;quot;)
     (:header
      (:h1 &amp;quot;Home page&amp;quot;))
     (:section
      (&amp;quot;~A, here is *your* shopping list: &amp;quot; *user-name*)
      (:ol (dolist (item *shopping-list*)
             (:li (1+ (random 10)) item))))
     (:footer (&amp;quot;Last login: ~A&amp;quot; *last-login*)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The author finds it is easier to compose the HTML in separate
functions and macros than with the more famous cl-who. But it
has more features under it sleeves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it warns on invalid tags and attributes&lt;/li&gt;
&lt;li&gt;it can automatically number headers, given their depth&lt;/li&gt;
&lt;li&gt;it pretty prints html per default, with control over line breaks&lt;/li&gt;
&lt;li&gt;it understands embedded markdown&lt;/li&gt;
&lt;li&gt;it can tell where in the document a generator function is (see &lt;code&gt;get-html-tag&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;connecting-to-a-database&#34;&gt;Connecting to a database&lt;/h1&gt;

&lt;p&gt;Please see the &lt;a href=&#34;databases.html&#34;&gt;databases section&lt;/a&gt;. The Mito ORM
supports SQLite3, PostgreSQL, MySQL, it has migrations and db schema
versioning, etc.&lt;/p&gt;

&lt;p&gt;In Caveman, a database connection is alive during the Lisp session and is
reused in each HTTP requests.&lt;/p&gt;

&lt;h2 id=&#34;checking-a-user-is-logged-in&#34;&gt;Checking a user is logged-in&lt;/h2&gt;

&lt;p&gt;A framework will provide a way to work with sessions. We&amp;rsquo;ll create a
little macro to wrap our routes to check if the user is logged in.&lt;/p&gt;

&lt;p&gt;In Caveman, &lt;code&gt;*session*&lt;/code&gt; is a hash table that represents the session&amp;rsquo;s
data. Here are our login and logout functions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun login (user)
  &amp;quot;Log the user into the session&amp;quot;
  (setf (gethash :user *session*) user))

(defun logout ()
  &amp;quot;Log the user out of the session.&amp;quot;
  (setf (gethash :user *session*) nil))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We define a simple predicate:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun logged-in-p ()
  (gethash :user cm:*session*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we define our &lt;code&gt;with-logged-in&lt;/code&gt; macro:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro with-logged-in (&amp;amp;body body)
  `(if (logged-in-p)
       (progn ,@body)
       (render #p&amp;quot;login.html&amp;quot;
               &#39;(:message &amp;quot;Please log-in to access this page.&amp;quot;))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the user isn&amp;rsquo;t logged in, there will nothing in the session store,
and we render the login page. When all is well, we execute the macro&amp;rsquo;s
body. We use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defroute &amp;quot;/account/logout&amp;quot; ()
  &amp;quot;Show the log-out page, only if the user is logged in.&amp;quot;
  (with-logged-in
    (logout)
    (render #p&amp;quot;logout.html&amp;quot;)))

(defroute (&amp;quot;/account/review&amp;quot; :method :get) ()
  (with-logged-in
    (render #p&amp;quot;review.html&amp;quot;
            (list :review (get-review (gethash :user *session*))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and so on.&lt;/p&gt;

&lt;h2 id=&#34;encrypting-passwords&#34;&gt;Encrypting passwords&lt;/h2&gt;

&lt;p&gt;In this recipe we use the de-facto standard
&lt;a href=&#34;https://github.com/froydnj/ironclad&#34;&gt;Ironclad&lt;/a&gt; cryptographic toolkit
and the &lt;a href=&#34;https://github.com/cl-babel/babel&#34;&gt;Babel&lt;/a&gt; charset
encoding/decoding library.&lt;/p&gt;

&lt;p&gt;This snippet creates the password hash that should be stored in your
database. Note that Ironclad expects a byte-vector, not a string.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun password-hash (password)
  (ironclad:pbkdf2-hash-password-to-combined-string
   (babel:string-to-octets password)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;pbkdf2&lt;/code&gt; is defined in &lt;a href=&#34;https://tools.ietf.org/html/rfc2898&#34;&gt;RFC2898&lt;/a&gt;.
It uses a pseudorandom function to derive a secure encryption key
based on the password.&lt;/p&gt;

&lt;p&gt;The following function checks if a user is active and verifies the
entered password. It returns the user-id if active and verified and
nil in all other cases even if an error occurs. Adapt it to your
application.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun check-user-password (user password)
  (handler-case
      (let* ((data (my-get-user-data user))
             (hash (my-get-user-hash data))
             (active (my-get-user-active data)))
        (when (and active (ironclad:pbkdf2-check-password (babel:string-to-octets password)
                                                          hash))
          (my-get-user-id data)))
    (condition () nil)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the following is an example on how to set the password on the
database. Note that we use &lt;code&gt;(password-hash password)&lt;/code&gt; to save the
password. The rest is specific to the web framework and to the DB
library.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun set-password (user password)
  (with-connection (db)
    (execute
     (make-statement :update :web_user
                     (set= :hash (password-hash password))
                     (make-clause :where
                                  (make-op := (if (integerp user)
                                                  :id_user
                                                  :email)
                                           user))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Credit: &lt;code&gt;/u/arvid&lt;/code&gt; on &lt;a href=&#34;https://www.reddit.com/r/learnlisp/comments/begcf9/can_someone_give_me_an_eli5_on_hiw_to_encrypt_and/&#34;&gt;/r/learnlisp&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h1 id=&#34;building&#34;&gt;Building&lt;/h1&gt;

&lt;h2 id=&#34;building-a-self-contained-executable&#34;&gt;Building a self-contained executable&lt;/h2&gt;

&lt;p&gt;As for all Common Lisp applications, we can bundle our web app in one
single executable, including the assets. It makes deployment very
easy: copy it to your server and run it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./my-web-app
Hunchentoot server is started.
Listening on localhost:9003.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See this recipe on &lt;a href=&#34;scripting.html#for-web-apps&#34;&gt;scripting#for-web-apps&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;continuous-delivery-with-travis-ci-or-gitlab-ci&#34;&gt;Continuous delivery with Travis CI or Gitlab CI&lt;/h2&gt;

&lt;p&gt;Please see the section on &lt;a href=&#34;testing.html#continuous-integration&#34;&gt;testing#continuous-integration&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;multiplatform-delivery-with-electron&#34;&gt;Multiplatform delivery with Electron&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://ceramic.github.io/&#34;&gt;Ceramic&lt;/a&gt; makes all the work for us.&lt;/p&gt;

&lt;p&gt;It is as simple as this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; Load Ceramic and our app
(ql:quickload &#39;(:ceramic :our-app))

;; Ensure Ceramic is set up
(ceramic:setup)
(ceramic:interactive)

;; Start our app (here based on the Lucerne framework)
(lucerne:start our-app.views:app :port 8000)

;; Open a browser window to it
(defvar window (ceramic:make-window :url &amp;quot;http://localhost:8000/&amp;quot;))

;; start Ceramic
(ceramic:show-window window)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and we can ship this on Linux, Mac and Windows.&lt;/p&gt;

&lt;p&gt;There is more:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ceramic applications are compiled down to native code, ensuring both performance and enabling you to deliver closed-source, commercial applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thus, no need to minify our JS.&lt;/p&gt;

&lt;h1 id=&#34;deployment&#34;&gt;Deployment&lt;/h1&gt;

&lt;h2 id=&#34;deploying-manually&#34;&gt;Deploying manually&lt;/h2&gt;

&lt;p&gt;We can start our executable in a shell and send it to the bakcground (&lt;code&gt;C-z bg&lt;/code&gt;), or run it inside a &lt;code&gt;tmux&lt;/code&gt; session. These are not the best but hey, it works©.&lt;/p&gt;

&lt;h2 id=&#34;daemonizing-restarting-in-case-of-crashes-handling-logs-with-systemd&#34;&gt;Daemonizing, restarting in case of crashes, handling logs with Systemd&lt;/h2&gt;

&lt;p&gt;This is actually a system-specific task. See how to do that on your system.&lt;/p&gt;

&lt;p&gt;Most GNU/Linux distros now come with Systemd, so here&amp;rsquo;s a little example.&lt;/p&gt;

&lt;p&gt;Deploying an app with Systemd is as simple as writing a configuration file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ emacs -nw /etc/systemd/system/my-app.service
[Unit]
Description=stupid simple example

[Service]
WorkingDirectory=/path/to/your/app
ExecStart=/usr/local/bin/sthg sthg
Type=simple
Restart=always
RestartSec=10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then we have a command to start it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo systemctl start my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;a command to check its status:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;systemctl status my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and Systemd can handle &lt;strong&gt;logging&lt;/strong&gt; (we write to stdout or stderr, it writes logs):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;journalctl -f -u my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it handles crashes and &lt;strong&gt;restarts the app&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Restart=always
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it can &lt;strong&gt;start the app after a reboot&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Install]
WantedBy=basic.target
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to enable it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo systemctl enable my-app.service
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;with-docker&#34;&gt;With Docker&lt;/h2&gt;

&lt;p&gt;There are several Docker images for Common
Lisp. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/base-lisp-image&#34;&gt;40ants/base-lisp-image&lt;/a&gt;
is based on Ubuntu LTS and includes SBCL, CCL, Quicklisp, Qlot and
Roswell.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/container-lisp/s2i-lisp&#34;&gt;container-lisp/s2i-lisp&lt;/a&gt;
is CentOs based and contains the source for building a Quicklisp based
Common Lisp application as a reproducible docker image using OpenShift&amp;rsquo;s
source-to-image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;with-guix&#34;&gt;With Guix&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/guix/&#34;&gt;GNU Guix&lt;/a&gt; is a transactional
package manager, that can be installed on top of an existing OS, and a
whole distro that supports declarative system configuration. It allows
to ship self-contained tarballs, which also contain system
dependencies. For an example, see the &lt;a href=&#34;https://github.com/atlas-engineer/next/&#34;&gt;Next browser&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;deploying-on-heroku-and-other-services&#34;&gt;Deploying on Heroku and other services&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&#34;https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp&#34;&gt;heroku-buildpack-common-lisp&lt;/a&gt; and the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#deployment&#34;&gt;Awesome CL#deploy&lt;/a&gt; section for interface libraries for Kubernetes, OpenShift, AWS, etc.&lt;/p&gt;

&lt;h2 id=&#34;monitoring&#34;&gt;Monitoring&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&#34;https://github.com/deadtrickster/prometheus.cl&#34;&gt;Prometheus.cl&lt;/a&gt;
for a Grafana dashboard for SBCL and Hunchentoot metrics (memory,
threads, requests per second,…).&lt;/p&gt;

&lt;h2 id=&#34;connecting-to-a-remote-lisp-image&#34;&gt;Connecting to a remote Lisp image&lt;/h2&gt;

&lt;p&gt;This this section: &lt;a href=&#34;debugging.html#remote-debugging&#34;&gt;debugging#remote-debugging&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;hot-reload&#34;&gt;Hot reload&lt;/h2&gt;

&lt;p&gt;This is an example from &lt;a href=&#34;https://github.com/stylewarning/quickutil/blob/master/quickutil-server/&#34;&gt;Quickutil&lt;/a&gt;. It is actually an automated version of the precedent section.&lt;/p&gt;

&lt;p&gt;It has a Makefile target:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;hot_deploy:
	$(call $(LISP), \
		(ql:quickload :quickutil-server) (ql:quickload :swank-client), \
		(swank-client:with-slime-connection (conn &amp;quot;localhost&amp;quot; $(SWANK_PORT)) \
			(swank-client:slime-eval (quote (handler-bind ((error (function continue))) \
				(ql:quickload :quickutil-utilities) (ql:quickload :quickutil-server) \
				(funcall (symbol-function (intern &amp;quot;STOP&amp;quot; :quickutil-server))) \
				(funcall (symbol-function (intern &amp;quot;START&amp;quot; :quickutil-server)) $(start_args)))) conn)) \
		$($(LISP)-quit))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It has to be run on the server (a simple fabfile command can call this
through ssh). Beforehand, a &lt;code&gt;fab update&lt;/code&gt; has run &lt;code&gt;git pull&lt;/code&gt; on the
server, so new code is present but not running. It connects to the
local swank server, loads the new code, stops and starts the app in a
row.&lt;/p&gt;

&lt;h1 id=&#34;credits&#34;&gt;Credits&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/web-dev/&#34;&gt;https://lisp-journey.gitlab.io/web-dev/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Pattern Matching in Common Lisp</title>
      <link>/blog/pattern-matching-in-common-lisp/</link>
      <pubDate>Sun, 26 May 2019 16:17:08 +0200</pubDate>
      
      <guid>/blog/pattern-matching-in-common-lisp/</guid>
      <description>

&lt;p&gt;New page on the Cookbook:
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/pattern_matching.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/pattern_matching.html&lt;/a&gt; All
examples come from Trivia&amp;rsquo;s wiki.&lt;/p&gt;

&lt;p&gt;The ANSI Common Lisp standard does not include facilities for pattern
matching, but libraries existed for this task and
&lt;a href=&#34;https://github.com/guicho271828/trivia&#34;&gt;Trivia&lt;/a&gt; became a community
standard.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#common-destructuring-patterns&#34;&gt;Common destructuring patterns&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#cons&#34;&gt;&lt;code&gt;cons&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#list-list&#34;&gt;&lt;code&gt;list&lt;/code&gt;, &lt;code&gt;list*&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#vector-vector&#34;&gt;&lt;code&gt;vector&lt;/code&gt;, &lt;code&gt;vector*&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#class-and-structure-pattern&#34;&gt;Class and structure pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#type-satisfies&#34;&gt;&lt;code&gt;type&lt;/code&gt;, &lt;code&gt;satisfies&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#assoc-property-alist-plist&#34;&gt;&lt;code&gt;assoc&lt;/code&gt;, &lt;code&gt;property&lt;/code&gt;, &lt;code&gt;alist&lt;/code&gt;, &lt;code&gt;plist&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#array-simple-array-row-major-array-patterns&#34;&gt;Array, simple-array, row-major-array patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#logic-based-patterns&#34;&gt;Logic based patterns&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#and-or&#34;&gt;&lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#not&#34;&gt;&lt;code&gt;not&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#guards&#34;&gt;&lt;code&gt;guards&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nesting-patterns&#34;&gt;Nesting patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#see-more&#34;&gt;See more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;p&gt;For an introduction to the concepts of pattern matching, see &lt;a href=&#34;https://github.com/guicho271828/trivia/wiki/What-is-pattern-matching%3F-Benefits%3F&#34;&gt;Trivia&amp;rsquo;s wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Trivia matches against &lt;em&gt;a lot&lt;/em&gt; of lisp objects and is extensible.&lt;/p&gt;

&lt;p&gt;The library is in Quicklisp:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;trivia&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the following examples, let&amp;rsquo;s &lt;code&gt;use&lt;/code&gt; the library:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(use-package :trivia)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;common-destructuring-patterns&#34;&gt;Common destructuring patterns&lt;/h2&gt;

&lt;h3 id=&#34;cons&#34;&gt;&lt;code&gt;cons&lt;/code&gt;&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match &#39;(1 2 3)
  ((cons x y)
  ; ^^ pattern
   (print x)
   (print y)))
;; |-&amp;gt; 1
;; |-&amp;gt; (2 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;list-list&#34;&gt;&lt;code&gt;list&lt;/code&gt;, &lt;code&gt;list*&lt;/code&gt;&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match &#39;(something #(0 1 2))
  ((list a (vector 0 _ b))
   (values a b)))
SOMETHING
2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;list*&lt;/code&gt; pattern:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match &#39;(1 2 . 3)
  ((list* _ _ x)
   x))
3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that using &lt;code&gt;list&lt;/code&gt; would match nothing.&lt;/p&gt;

&lt;h3 id=&#34;vector-vector&#34;&gt;&lt;code&gt;vector&lt;/code&gt;, &lt;code&gt;vector*&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;vector&lt;/code&gt; checks if the object is a vector, if the lengths are the
same, and if the contents matches against each subpatterns.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vector*&lt;/code&gt; is similar, but called a soft-match variant that allows if
the length is larger-than-equal to the length of subpatterns.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match #(1 2 3)
  ((vector _ x _)
   x))
;; -&amp;gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match #(1 2 3 4)
  ((vector _ x _)
   x))
;; -&amp;gt; NIL : does not match
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match #(1 2 3 4)
  ((vector* _ x _)
   x))
;; -&amp;gt; 2 : soft match.
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;vector-pattern&amp;gt; : vector      | simple-vector
                   bit-vector  | simple-bit-vector
                   string      | simple-string
                   base-string | simple-base-string | sequence
(&amp;lt;vector-pattern&amp;gt; &amp;amp;rest subpatterns)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;class-and-structure-pattern&#34;&gt;Class and structure pattern&lt;/h3&gt;

&lt;p&gt;There are three styles that are equivalent:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct foo bar baz)
(defvar *x* (make-foo :bar 0 :baz 1)

(match *x*
  ;; make-instance style
  ((foo :bar a :baz b)
   (values a b))
  ;; with-slots style
  ((foo (bar a) (baz b))
   (values a b))
  ;; slot name style
  ((foo bar baz)
   (values bar baz)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;type-satisfies&#34;&gt;&lt;code&gt;type&lt;/code&gt;, &lt;code&gt;satisfies&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; pattern matches if the object is of type. &lt;code&gt;satisfies&lt;/code&gt; matches
if the predicate returns true for the object. A lambda form is
acceptable.&lt;/p&gt;

&lt;h3 id=&#34;assoc-property-alist-plist&#34;&gt;&lt;code&gt;assoc&lt;/code&gt;, &lt;code&gt;property&lt;/code&gt;, &lt;code&gt;alist&lt;/code&gt;, &lt;code&gt;plist&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;All these patterns first check if the pattern is a list. If that is
satisfied, then they obtain the contents, and the value is matched
against the subpattern.&lt;/p&gt;

&lt;h3 id=&#34;array-simple-array-row-major-array-patterns&#34;&gt;Array, simple-array, row-major-array patterns&lt;/h3&gt;

&lt;p&gt;See &lt;a href=&#34;https://github.com/guicho271828/trivia/wiki/Type-Based-Destructuring-Patterns#array-simple-array-row-major-array-pattern&#34;&gt;https://github.com/guicho271828/trivia/wiki/Type-Based-Destructuring-Patterns#array-simple-array-row-major-array-pattern&lt;/a&gt; !&lt;/p&gt;

&lt;h2 id=&#34;logic-based-patterns&#34;&gt;Logic based patterns&lt;/h2&gt;

&lt;h3 id=&#34;and-or&#34;&gt;&lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match x
  ((or (list 1 a)
       (cons a 3))
   a))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;matches against both &lt;code&gt;(1 2)&lt;/code&gt; and &lt;code&gt;(4 . 3)&lt;/code&gt; and returns 2 and 4, respectively.&lt;/p&gt;

&lt;h3 id=&#34;not&#34;&gt;&lt;code&gt;not&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;It does not match when subpattern matches. The variables used in the
subpattern are not visible in the body.&lt;/p&gt;

&lt;h3 id=&#34;guards&#34;&gt;&lt;code&gt;guards&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The syntax is &lt;code&gt;guard&lt;/code&gt; + &lt;code&gt;subpattern&lt;/code&gt; + &lt;code&gt;a test form&lt;/code&gt;, and the body.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match (list 2 5)
  ((guard (list x y)     ; subpattern
          (= 10 (* x y)) ; test-form
          (- x y) (satisfies evenp)) ; generator1, subpattern1
   t))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the subpattern is true, the test form is evaluated, and if it is
true it is matched against subpattern1.&lt;/p&gt;

&lt;p&gt;The above returns &lt;code&gt;nil&lt;/code&gt;, since &lt;code&gt;(- x y) == 3&lt;/code&gt; does not satisfies &lt;code&gt;evenp&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;nesting-patterns&#34;&gt;Nesting patterns&lt;/h2&gt;

&lt;p&gt;Patterns can be nested:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(match &#39;(:a (3 4) 5)
  ((list :a (list _ c) _)
   c))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;returns &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;see-more&#34;&gt;See more&lt;/h2&gt;

&lt;p&gt;See &lt;a href=&#34;https://github.com/guicho271828/trivia/wiki/Special-Patterns&#34;&gt;special patterns&lt;/a&gt;: &lt;code&gt;place&lt;/code&gt;, &lt;code&gt;bind&lt;/code&gt; and &lt;code&gt;access&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Functions Tutorial: Arguments, Multiple Values, funcall and apply, closures and more</title>
      <link>/blog/functions-tutorial-arguments-multiple-values-more/</link>
      <pubDate>Sun, 26 May 2019 16:08:10 +0200</pubDate>
      
      <guid>/blog/functions-tutorial-arguments-multiple-values-more/</guid>
      <description>

&lt;p&gt;Here&amp;rsquo;s an enhanced page for the Cookbook: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/functions.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/functions.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only the Currying part was untouched (we enhanced it already), the
higher-order functions part existed and was rewritten. The rest is
new, and it should help you start writing Common Lisp quicker than
ever.&lt;/p&gt;

&lt;p&gt;Happy lisping !&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-refresh-toc --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#named-functions-defun&#34;&gt;Named functions: &lt;code&gt;defun&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#arguments&#34;&gt;Arguments&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#base-case-required-arguments&#34;&gt;Base case: required arguments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#optional-arguments-optional&#34;&gt;Optional arguments: &lt;code&gt;&amp;amp;optional&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#named-parameters-key&#34;&gt;Named parameters: &lt;code&gt;&amp;amp;key&lt;/code&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#mixing-optional-and-key-parameters&#34;&gt;Mixing optional and key parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#default-values&#34;&gt;Default values&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#variable-number-of-arguments-rest&#34;&gt;Variable number of arguments: &lt;code&gt;&amp;amp;rest&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#allow-other-keys&#34;&gt;&lt;code&gt;&amp;amp;allow-other-keys&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#return-values&#34;&gt;Return values&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#multiple-return-values-values-and-multiple-value-bind&#34;&gt;Multiple return values: &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;multiple-value-bind&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#anonymous-functions-lambda&#34;&gt;Anonymous functions: &lt;code&gt;lambda&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#calling-functions-programatically-funcall-and-apply&#34;&gt;Calling functions programatically: &lt;code&gt;funcall&lt;/code&gt; and &lt;code&gt;apply&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#higher-order-functions-functions-that-return-functions&#34;&gt;Higher order functions: functions that return functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#closures&#34;&gt;Closures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#setf-functions&#34;&gt;&lt;code&gt;setf&lt;/code&gt; functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#currying&#34;&gt;Currying&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#concept&#34;&gt;Concept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-the-alexandria-library&#34;&gt;With the Alexandria library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#documentation&#34;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;named-functions-defun&#34;&gt;Named functions: &lt;code&gt;defun&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Creating named functions is done with the &lt;code&gt;defun&lt;/code&gt; keyword. It follows this model:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun &amp;lt;name&amp;gt; (list of arguments)
  &amp;quot;docstring&amp;quot;
  (function body))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The return value is the value returned by the last expression of the body
(see below for more). There is no &amp;ldquo;return xx&amp;rdquo; statement.&lt;/p&gt;

&lt;p&gt;So, for example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello-world ()
  ;;               ^^ no arguments
  (print &amp;quot;hello world!&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Call it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hello-world)
;; &amp;quot;hello world!&amp;quot;  &amp;lt;-- output
;; &amp;quot;hello world!&amp;quot;  &amp;lt;-- a string is returned.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;arguments&#34;&gt;Arguments&lt;/h2&gt;

&lt;h3 id=&#34;base-case-required-arguments&#34;&gt;Base case: required arguments&lt;/h3&gt;

&lt;p&gt;Add in arguments like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name)
  &amp;quot;Say hello to `name&#39;.&amp;quot;
  (format t &amp;quot;hello ~a !~&amp;amp;&amp;quot; name))
;; HELLO
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(where &lt;code&gt;~a&lt;/code&gt; is the most used &lt;code&gt;format&lt;/code&gt; directive to print a variable
&lt;em&gt;aesthetically&lt;/em&gt; and &lt;code&gt;~&amp;amp;&lt;/code&gt; prints a newline)&lt;/p&gt;

&lt;p&gt;Call the function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hello &amp;quot;me&amp;quot;)
;; hello me !  &amp;lt;-- this is printed by `format`
;; NIL         &amp;lt;-- return value: `format t` prints a string to standard output and returns nil.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you don&amp;rsquo;t specify the right amount of arguments, you&amp;rsquo;ll be trapped
into the interactive debugger with an explicit error message:&lt;/p&gt;

&lt;p&gt;(hello)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;invalid number of arguments: 0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;optional-arguments-optional&#34;&gt;Optional arguments: &lt;code&gt;&amp;amp;optional&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Optional arguments are declared after the &lt;code&gt;&amp;amp;optional&lt;/code&gt; keyword in the
lambda list. They are ordered, they must appear one after another.&lt;/p&gt;

&lt;p&gt;This function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name &amp;amp;optional age gender) …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;must be called like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hello &amp;quot;me&amp;quot;) ;; a value for the required argument, zero optional arguments
(hello &amp;quot;me&amp;quot; &amp;quot;7&amp;quot;)  ;; a value for age
(hello &amp;quot;me&amp;quot; 7 :h) ;; a value for age and gender
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;named-parameters-key&#34;&gt;Named parameters: &lt;code&gt;&amp;amp;key&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;It is not always convenient to remember the order of the arguments. It
is thus possible to supply arguments by name: we declare them using
&lt;code&gt;&amp;amp;key &amp;lt;name&amp;gt;&lt;/code&gt;, we set them with &lt;code&gt;:name &amp;lt;value&amp;gt;&lt;/code&gt; in the function call,
and we use &lt;code&gt;name&lt;/code&gt; as a regular variable in the function body. They are
&lt;code&gt;nil&lt;/code&gt; by default.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name &amp;amp;key happy)
  &amp;quot;If `happy&#39; is `t&#39;, print a smiley&amp;quot;
  (format t &amp;quot;hello ~a &amp;quot; name)
  (when happy
    (format t &amp;quot;:)~&amp;amp;&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following calls are possible:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(hello &amp;quot;me&amp;quot;)
(hello &amp;quot;me&amp;quot; :happy t)
(hello &amp;quot;me&amp;quot; :happy nil) ;; useless, equivalent to (hello &amp;quot;me&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and this is not valid: &lt;code&gt;(hello &amp;quot;me&amp;quot; :happy)&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;odd number of &amp;amp;KEY arguments&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A similar example of a function declaration, with several key parameters:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name &amp;amp;key happy lisper cookbook-contributor-p) …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it can be called with zero or more key parameters, in any order:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hello &amp;quot;me&amp;quot; :lisper t)
(hello &amp;quot;me&amp;quot; :lisper t :happy t)
(hello &amp;quot;me&amp;quot; :cookbook-contributor-p t :happy t)
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;mixing-optional-and-key-parameters&#34;&gt;Mixing optional and key parameters&lt;/h4&gt;

&lt;p&gt;It is generally a style warning, but it is possible.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (&amp;amp;optional name &amp;amp;key happy)
  (format t &amp;quot;hello ~a &amp;quot; name)
  (when happy
    (format t &amp;quot;:)~&amp;amp;&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In SBCL, this yields:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;; in: DEFUN HELLO
;     (SB-INT:NAMED-LAMBDA HELLO
;         (&amp;amp;OPTIONAL NAME &amp;amp;KEY HAPPY)
;       (BLOCK HELLO (FORMAT T &amp;quot;hello ~a &amp;quot; NAME) (WHEN HAPPY (FORMAT T &amp;quot;:)~&amp;amp;&amp;quot;))))
;
; caught STYLE-WARNING:
;   &amp;amp;OPTIONAL and &amp;amp;KEY found in the same lambda list: (&amp;amp;OPTIONAL (NAME &amp;quot;John&amp;quot;) &amp;amp;KEY
;                                                      HAPPY)
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can call it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(hello &amp;quot;me&amp;quot; :happy t)
;; hello me :)
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;default-values&#34;&gt;Default values&lt;/h3&gt;

&lt;p&gt;In the lambda list, use pairs to give a default value to an optional or a key argument, like &lt;code&gt;(happy t)&lt;/code&gt; below:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name &amp;amp;key (happy t))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now &lt;code&gt;happy&lt;/code&gt; is true by default.&lt;/p&gt;

&lt;h3 id=&#34;variable-number-of-arguments-rest&#34;&gt;Variable number of arguments: &lt;code&gt;&amp;amp;rest&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Sometimes you want a function to accept a variable number of
arguments. Use &lt;code&gt;&amp;amp;rest &amp;lt;variable&amp;gt;&lt;/code&gt;, where &lt;code&gt;&amp;lt;variable&amp;gt;&lt;/code&gt; will be a list.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun mean (x &amp;amp;rest numbers)
    (/ (apply #&#39;+ x numbers)
       (1+ (length numbers))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mean 1)
(mean 1 2)
(mean 1 2 3 4 5)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;allow-other-keys&#34;&gt;&lt;code&gt;&amp;amp;allow-other-keys&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Observe:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name &amp;amp;key happy)
  (format t &amp;quot;hello ~a~&amp;amp;&amp;quot; name))

(hello &amp;quot;me&amp;quot; :lisper t)
;; =&amp;gt; Error: unknown keyword argument
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;whereas&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun hello (name &amp;amp;key happy &amp;amp;allow-other-keys)
  (format t &amp;quot;hello ~a~&amp;amp;&amp;quot; name))

(hello &amp;quot;me&amp;quot; :lisper t)
;; hello me
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We might need &lt;code&gt;&amp;amp;allow-other-keys&lt;/code&gt; when passing around arguments or
with higher level manipulation of functions.&lt;/p&gt;

&lt;h2 id=&#34;return-values&#34;&gt;Return values&lt;/h2&gt;

&lt;p&gt;The return value of the function is the value returned by the last
executed form of the body.&lt;/p&gt;

&lt;p&gt;There are ways for non-local exits (&lt;code&gt;return-from &amp;lt;function name&amp;gt; &amp;lt;value&amp;gt;&lt;/code&gt;), but they are usually not needed.&lt;/p&gt;

&lt;p&gt;Common Lisp has also the concept of multiple return values.&lt;/p&gt;

&lt;h3 id=&#34;multiple-return-values-values-and-multiple-value-bind&#34;&gt;Multiple return values: &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;multiple-value-bind&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Returning multiple values is &lt;em&gt;not&lt;/em&gt; like returning a tuple or a list of
results ;) This is a common misconception.&lt;/p&gt;

&lt;p&gt;Multiple values are specially useful and powerful because a change in
them needs little to no refactoring.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun foo (a b c)
  a)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This function returns &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *res* (foo :a :b :c))
;; :A
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use &lt;code&gt;values&lt;/code&gt; to return multiple values:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun foo (a b c)
  (values a b c))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf *res* (foo :a :b :c))
;; :A
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Observe here that &lt;code&gt;*res*&lt;/code&gt; &lt;em&gt;is still &lt;code&gt;:A&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;All functions that use the return value of &lt;code&gt;foo&lt;/code&gt; need no change, they
still work. If we had returned a list or an array, this would be
different.&lt;/p&gt;

&lt;p&gt;We destructure multiple values with &lt;code&gt;multiple-value-bind&lt;/code&gt; (or
&lt;code&gt;mvb&lt;/code&gt;+TAB in Slime for short):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(multiple-value-bind (res1 res2 res3)
    (foo :a :b :c)
  (format t &amp;quot;res1 is ~a, res2 is ~a, res2 is ~a~&amp;amp;&amp;quot; res1 res2 res3))
;; res1 is A, res2 is B, res2 is C
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Its general form is&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(multiple-value-bind (var-1 .. var-n) expr
  body)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The variables &lt;code&gt;var-n&lt;/code&gt; are not available outside the scope of &lt;code&gt;multiple-value-bind&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Last but not least: note that &lt;code&gt;(values)&lt;/code&gt; with no values returns… no values at all.&lt;/p&gt;

&lt;p&gt;See also &lt;code&gt;multiple-value-call&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;anonymous-functions-lambda&#34;&gt;Anonymous functions: &lt;code&gt;lambda&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Anonymous functions are created with &lt;code&gt;lambda&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lambda (x) (print x))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can call a lambda with &lt;code&gt;funcall&lt;/code&gt; or &lt;code&gt;apply&lt;/code&gt; (see below).&lt;/p&gt;

&lt;p&gt;If the first element of an unquoted list is a lambda expression, the
lambda is called:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;((lambda (x) (print x)) &amp;quot;hello&amp;quot;)
;; hello
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;calling-functions-programatically-funcall-and-apply&#34;&gt;Calling functions programatically: &lt;code&gt;funcall&lt;/code&gt; and &lt;code&gt;apply&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;funcall&lt;/code&gt; is to be used with a known number of arguments, when &lt;code&gt;apply&lt;/code&gt;
can be used on a list, for example from &lt;code&gt;&amp;amp;rest&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(funcall #&#39;+ 1 2)
(apply #&#39;+ &#39;(1 2))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;higher-order-functions-functions-that-return-functions&#34;&gt;Higher order functions: functions that return functions&lt;/h2&gt;

&lt;p&gt;Writing functions that return functions is simple enough:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun adder (n)
  (lambda (x) (+ x n)))
;; ADDER
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we have defined the function &lt;code&gt;adder&lt;/code&gt; which returns an &lt;em&gt;object&lt;/em&gt; of &lt;em&gt;type&lt;/em&gt; &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm&#34;&gt;&lt;code&gt;function&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To call the resulting function, we must use &lt;code&gt;funcall&lt;/code&gt; or &lt;code&gt;apply&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(adder 5)
;; #&amp;lt;CLOSURE (LAMBDA (X) :IN ADDER) {100994ACDB}&amp;gt;
(funcall (adder 5) 3)
;; 8
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Trying to call it right away leads to an illegal function call:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;((adder 3) 5)
In: (ADDER 3) 5
    ((ADDER 3) 5)
Error: Illegal function call.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Indeed, CL has different &lt;em&gt;namespaces&lt;/em&gt; for functions and variables, i.e. the same &lt;em&gt;name&lt;/em&gt; can refer to different things depending on its position in a form that&amp;rsquo;s evaluated.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; The symbol foo is bound to nothing:
CL-USER&amp;gt; (boundp &#39;foo)
NIL
CL-USER&amp;gt; (fboundp &#39;foo)
NIL
;; We create a variable:
CL-USER&amp;gt; (defparameter foo 42)
FOO
* foo
42
;; Now foo is &amp;quot;bound&amp;quot;:
CL-USER&amp;gt; (boundp &#39;foo)
T
;; but still not as a function:
CL-USER&amp;gt; (fboundp &#39;foo)
NIL
;; So let&#39;s define a function:
CL-USER&amp;gt; (defun foo (x) (* x x))
FOO
;; Now the symbol foo is bound as a function too:
CL-USER&amp;gt; (fboundp &#39;foo)
T
;; Get the function:
CL-USER&amp;gt; (function foo)
#&amp;lt;FUNCTION FOO&amp;gt;
;; and the shorthand notation:
* #&#39;foo
#&amp;lt;FUNCTION FOO&amp;gt;
;; We call it:
(funcall (function adder) 5)
#&amp;lt;CLOSURE (LAMBDA (X) :IN ADDER) {100991761B}&amp;gt;
;; and call the lambda:
(funcall (funcall (function adder) 5) 3)
8
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To simplify a bit, you can think of each symbol in CL having (at least) two &amp;ldquo;cells&amp;rdquo; in which information is stored. One cell - sometimes referred to as its &lt;em&gt;value cell&lt;/em&gt; - can hold a value that is &lt;em&gt;bound&lt;/em&gt; to this symbol, and you can use &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_boundp.htm&#34;&gt;&lt;code&gt;boundp&lt;/code&gt;&lt;/a&gt; to test whether the symbol is bound to a value (in the global environment). You can access the value cell of a symbol with &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_5.htm&#34;&gt;&lt;code&gt;symbol-value&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The other cell - sometimes referred to as its &lt;em&gt;function cell&lt;/em&gt; - can hold the definition of the symbol&amp;rsquo;s (global) function binding. In this case, the symbol is said to be &lt;em&gt;fbound&lt;/em&gt; to this definition. You can use &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_fbound.htm&#34;&gt;&lt;code&gt;fboundp&lt;/code&gt;&lt;/a&gt; to test whether a symbol is fbound. You can access the function cell of a symbol (in the global environment) with &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_1.htm&#34;&gt;&lt;code&gt;symbol-function&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, if a &lt;em&gt;symbol&lt;/em&gt; is evaluated, it is treated as a &lt;em&gt;variable&lt;/em&gt; in that its value cell is returned (just &lt;code&gt;foo&lt;/code&gt;). If a &lt;em&gt;compound form&lt;/em&gt;, i.e. a &lt;em&gt;cons&lt;/em&gt;, is evaluated and its &lt;em&gt;car&lt;/em&gt; is a symbol, then the function cell of this symbol is used (as in &lt;code&gt;(foo 3)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In Common Lisp, as opposed to Scheme, it is &lt;em&gt;not&lt;/em&gt; possible that the car of the compound form to be evaluated is an arbitrary form. If it is not a symbol, it &lt;em&gt;must&lt;/em&gt; be a &lt;em&gt;lambda expression&lt;/em&gt;, which looks like &lt;code&gt;(lambda&lt;/code&gt;&lt;em&gt;lambda-list&lt;/em&gt; &lt;em&gt;form*&lt;/em&gt;&lt;code&gt;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This explains the error message we got above - &lt;code&gt;(adder 3)&lt;/code&gt; is neither a symbol nor a lambda expression.&lt;/p&gt;

&lt;p&gt;If we want to be able to use the symbol &lt;code&gt;*my-fun*&lt;/code&gt; in the car of a compound form, we have to explicitely store something in its &lt;em&gt;function cell&lt;/em&gt; (which is normally done for us by the macro &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/m_defun.htm&#34;&gt;&lt;code&gt;defun&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; continued from above
CL-USER&amp;gt; (fboundp &#39;*my-fun*)
NIL
CL-USER&amp;gt; (setf (symbol-function &#39;*my-fun*) (adder 3))
#&amp;lt;CLOSURE (LAMBDA (X) :IN ADDER) {10099A5EFB}&amp;gt;
CL-USER&amp;gt; (fboundp &#39;*my-fun*)
T
CL-USER&amp;gt; (*my-fun* 5)
8
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Read the CLHS section about &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/03_aba.htm&#34;&gt;form evaluation&lt;/a&gt; for more.&lt;/p&gt;

&lt;h2 id=&#34;closures&#34;&gt;Closures&lt;/h2&gt;

&lt;p&gt;Closures allow to capture lexical bindings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((limit 3)
      (counter -1))
    (defun my-counter ()
      (if (&amp;lt; counter limit)
          (incf counter)
          (setf counter 0))))

(my-counter)
0
(my-counter)
1
(my-counter)
2
(my-counter)
3
(my-counter)
0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or similarly:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun repeater (n)
  (let ((counter -1))
     (lambda ()
       (if (&amp;lt; counter n)
         (incf counter)
         (setf counter 0)))))

(defparameter *my-repeater* (repeater 3))
;; *MY-REPEATER*
(funcall *my-repeater*)
0
(funcall *my-repeater*)
1
(funcall *my-repeater*)
2
(funcall *my-repeater*)
3
(funcall *my-repeater*)
0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See more on &lt;a href=&#34;http://www.gigamonkeys.com/book/variables.html&#34;&gt;Practical Common Lisp&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;setf-functions&#34;&gt;&lt;code&gt;setf&lt;/code&gt; functions&lt;/h2&gt;

&lt;p&gt;A function name can also be a list of two symbols with &lt;code&gt;setf&lt;/code&gt; as the
first one, and where the first argument is the new value:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun (setf &amp;lt;name&amp;gt;) (new-value &amp;lt;other arguments&amp;gt;)
  body)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This mechanism is particularly used for CLOS methods.&lt;/p&gt;

&lt;p&gt;A silly example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *current-name* &amp;quot;&amp;quot;
  &amp;quot;A global name.&amp;quot;)

(defun hello (name)
  (format t &amp;quot;hello ~a~&amp;amp;&amp;quot; name))

(defun (setf hello) (new-value)
  (hello new-value)
  (setf *current-name* new-value)
  (format t &amp;quot;current name is now ~a~&amp;amp;&amp;quot; new-value))

(setf (hello) &amp;quot;Alice&amp;quot;)
;; hello Alice
;; current name is now Alice
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;curry&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;currying&#34;&gt;Currying&lt;/h2&gt;

&lt;h3 id=&#34;concept&#34;&gt;Concept&lt;/h3&gt;

&lt;p&gt;A related concept is that of &lt;em&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Currying&#34;&gt;currying&lt;/a&gt;&lt;/em&gt; which you might be familiar with if you&amp;rsquo;re coming from a functional language. After we&amp;rsquo;ve read the last section that&amp;rsquo;s rather easy to implement:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (declaim (ftype (function (function &amp;amp;rest t) function) curry) (inline curry))
NIL
CL-USER&amp;gt; (defun curry (function &amp;amp;rest args)
           (lambda (&amp;amp;rest more-args)
	           (apply function (append args more-args))))
CURRY
CL-USER&amp;gt; (funcall (curry #&#39;+ 3) 5)
8
CL-USER&amp;gt; (funcall (curry #&#39;+ 3) 6)
9
CL-USER&amp;gt; (setf (symbol-function &#39;power-of-ten) (curry #&#39;expt 10))
#&amp;lt;Interpreted Function &amp;quot;LAMBDA (FUNCTION &amp;amp;REST ARGS)&amp;quot; {482DB969}&amp;gt;
CL-USER&amp;gt; (power-of-ten 3)
1000
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/m_declai.htm&#34;&gt;&lt;code&gt;declaim&lt;/code&gt;&lt;/a&gt; statement above is just a hint for the compiler so it can produce more efficient code if it so wishes. Leaving it out won&amp;rsquo;t change the semantics of the function.&lt;/p&gt;

&lt;h3 id=&#34;with-the-alexandria-library&#34;&gt;With the Alexandria library&lt;/h3&gt;

&lt;p&gt;Now that you know how to do it, you may appreciate using the
implementation of the
&lt;a href=&#34;https://common-lisp.net/project/alexandria/draft/alexandria.html#Data-and-Control-Flow&#34;&gt;Alexandria&lt;/a&gt;
library (in Quicklisp).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :alexandria)

(defun adder (foo bar)
  &amp;quot;Add the two arguments.&amp;quot;
  (+ foo bar))

(defvar add-one (alexandria:curry #&#39;adder 1) &amp;quot;Add 1 to the argument.&amp;quot;)

(funcall add-one 10)  ;; =&amp;gt; 11

(setf (symbol-function &#39;add-one) add-one)
(add-one 10)  ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;documentation&#34;&gt;Documentation&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;functions: &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function&#34;&gt;http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ordinary lambda lists: &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/03_da.htm&#34;&gt;http://www.lispworks.com/documentation/HyperSpec/Body/03_da.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;multiple-value-bind: &lt;a href=&#34;http://clhs.lisp.se/Body/m_multip.htm&#34;&gt;http://clhs.lisp.se/Body/m_multip.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>I Now Work Professionally in Common Lisp O_o</title>
      <link>/blog/i-now-work-professionally-in-common-lisp/</link>
      <pubDate>Mon, 20 May 2019 18:48:31 +0200</pubDate>
      
      <guid>/blog/i-now-work-professionally-in-common-lisp/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been paid to work on Common Lisp projects for a company for three
months already. I didn&amp;rsquo;t expect it :) And we did hire !&lt;/p&gt;

&lt;p&gt;My Github profile shows a good part of what my experience is. I am a
regular &amp;ldquo;full stack developper&amp;rdquo;, with 7 years of professional
experience. I worked on diverse Python and Javascript projects for
huge to small companies, private and public. When I re-discovered
Common Lisp, I saw it solved a lot of problems I had developing and
deploying medium to large software, and it promised to solve all of
them (we&amp;rsquo;re nearly there :D ). I started to write about my experience
on this blog and I contributed to open source projects, of which a lot
of documentation effort. It is this public activity that drew the
attention of the guys at &lt;a href=&#34;http://atlas.engineer/&#34;&gt;Atlas&lt;/a&gt;, who
contacted me, without a job announce. We developed and we maintain
a proprietary and successful web application that paid the bills, in
Common Lisp of course, and we work hard on other projects, such as the
&lt;a href=&#34;http://next.atlas.engineer/&#34;&gt;Next browser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, I can only encourage you to start a Common Lisp project, to come
enhance libraries and documentation and to write about it !  There are
few official job announces, some are posted on reddit, and some jobs
just won&amp;rsquo;t have a public announce. You&amp;rsquo;d better be ready.&lt;/p&gt;

&lt;p&gt;For the curious, our web app is rather classic, it uses the Caveman
web framework and is deployed on DigitalOcean. We do deploy with zero
downtime, as CL permits, for trivial updates (we are more cautious
otherwise). I&amp;rsquo;ll post its name in the comments if/when I know I can.&lt;/p&gt;

&lt;p&gt;Happy lisping.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>TIL how to interactively fix a failing test</title>
      <link>/blog/til-how-to-interactively-fix-a-failing-test/</link>
      <pubDate>Tue, 12 Mar 2019 13:10:27 +0200</pubDate>
      
      <guid>/blog/til-how-to-interactively-fix-a-failing-test/</guid>
      <description>&lt;p&gt;I knew it was possible, but I got to try it recently.&lt;/p&gt;

&lt;p&gt;Here I run a test with &lt;code&gt;fiveam&lt;/code&gt;. It fails. I tell &lt;code&gt;fiveam&lt;/code&gt; to enter
the debugger on failures with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(setf 5am:*on-error* :debug)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so we have an immediate feedback and we can re-run the test from where
it left off by choosing the appropriate restart.&lt;/p&gt;

&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/KsHxgP3SRTs&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Other test frameworks like &lt;a href=&#34;https://github.com/Shinmera/parachute&#34;&gt;Parachute&lt;/a&gt; allow that.&lt;/p&gt;

&lt;p&gt;This is one of the things that make development in Common Lisp
enjoyable and faster than with other workflows. Also, it&amp;rsquo;s built-in,
there is no fancy editor plugin or configuration.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;In the debugger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;enter&amp;gt;&lt;/code&gt; on a backtrace shows more of it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v&lt;/code&gt; on a backtrace goes to the corresponding line or function.&lt;/li&gt;
&lt;li&gt;more options with the menu.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>These Years in Common Lisp 2018</title>
      <link>/blog/these-years-in-common-lisp-2018/</link>
      <pubDate>Thu, 28 Feb 2019 14:42:46 +0100</pubDate>
      
      <guid>/blog/these-years-in-common-lisp-2018/</guid>
      <description>

&lt;p&gt;It&amp;rsquo;s been already a little more than a year that I began my Lisp
journey. I made quaterly news digests, mainly from reddit&amp;rsquo;s
feed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/these-months-in-common-lisp-q1-2018/&#34;&gt;Q1 2018&lt;/a&gt; - &lt;a href=&#34;/blog/these-months-in-common-lisp-q2-2018/&#34;&gt;Q2 2018&lt;/a&gt; - &lt;a href=&#34;/blog/these-months-in-common-lisp-q3-2018/&#34;&gt;Q3 2018&lt;/a&gt; - &lt;a href=&#34;/blog/these-months-in-common-lisp-q4-2018/&#34;&gt;Q4 2018&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Time has come for a yearly overview ! What happened in the Common Lisp
world ? Are there (or groundbreaking promising useful fun) projects,
articles, discussions, tutorials ?&lt;/p&gt;

&lt;p&gt;No need to say, I won&amp;rsquo;t reference everything we find in the quaterly
posts, which don&amp;rsquo;t list all new projects appearing on Quicklisp (we
can find these in the
&lt;a href=&#34;http://blog.quicklisp.org&#34;&gt;monthly Quicklisp releases&lt;/a&gt;) or Github.&lt;/p&gt;

&lt;p&gt;I hope this overview will sharpen your interest on what is in my
opinion an under-sold and still very promising language and plateform,
that I happen to like more and more (and sooo more than Python ;) ).&lt;/p&gt;

&lt;p&gt;Happy discoveries.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#documentation&#34;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#implementations&#34;&gt;Implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#projects&#34;&gt;Projects&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#new-projects&#34;&gt;New projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#web&#34;&gt;Web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gui&#34;&gt;GUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#package-management&#34;&gt;Package management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deployment&#34;&gt;Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#music&#34;&gt;Music&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rediscoveries&#34;&gt;(re)Discoveries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#articles&#34;&gt;Articles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-screencasts&#34;&gt;Other screencasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#discussion&#34;&gt;Discussion&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#learning-lisp&#34;&gt;Learning Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#common-lisp-vs-&#34;&gt;Common Lisp VS &amp;hellip;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;p&gt;Common Lisp&amp;rsquo;s online documentation could be more thorough and
welcoming. Fortunately, a few of us revived some projects and work on
it -my favourite project being the Common Lisp Coobook. This year, we
got tutorials on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/data-structures.html&#34;&gt;Datastructures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html&#34;&gt;Debugging&lt;/a&gt;, including how to interactively debug a spacecraft,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;the Common Lisp Object System (CLOS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/iteration.html&#34;&gt;Loop, iteration, mapping&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;Database access and persistence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/error_handling.html&#34;&gt;Error and condition handling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/numbers.html&#34;&gt;Numbers&lt;/a&gt; and &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/arrays.html&#34;&gt;multidimensional arrays&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html&#34;&gt;Scripting and building self-contained executables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/type.html&#34;&gt;Working with types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;along with many improvements on other pages, like on &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/getting-started.html&#34;&gt;getting started&lt;/a&gt; and &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/editor-support.html&#34;&gt;editor support&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which brings me to it: the editors situation is much more open than
you think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The editor of choice is still &lt;strong&gt;Emacs&lt;/strong&gt; with Slime (or
Sly),&lt;/li&gt;
&lt;li&gt;However, we can get started with Emacs and Lisp in 3 clicks with &lt;strong&gt;Portacle&lt;/strong&gt;, a &lt;em&gt;self-contained batteries-included sbcl-included portable&lt;/em&gt; Emacs tailored for CL,&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Vim&lt;/strong&gt; and &lt;strong&gt;NeoVim&lt;/strong&gt; we have SLIMV, VLIME, and plugins can be written for NeoVim using &lt;a href=&#34;https://github.com/adolenc/cl-neovim&#34;&gt;cl-neovim&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Or if we want an editor written in  cl, there&amp;rsquo;s the self-contained &lt;strong&gt;Lem&lt;/strong&gt; editor, which also works for Python, Go, Rust, Nim, Scheme, HTML, JSX, along with a directory mode, an experimental LSP mode, calc-mode, and more,&lt;/li&gt;
&lt;li&gt;Not to forget that Mac Os X users can use the &lt;a href=&#34;https://ccl.clozure.com/docs/ccl.html#the-clozure-cl-ide&#34;&gt;Clozure Common Lisp IDE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;All editions of LispWorks (including the free) include the &lt;a href=&#34;http://www.lispworks.com/products/ide.html&#34;&gt;LW IDE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For users of &lt;strong&gt;Eclipse IDE&lt;/strong&gt;, there is the Dandelion plugin&lt;/li&gt;
&lt;li&gt;For popular editors, the experience is getting very good on &lt;strong&gt;Atom&lt;/strong&gt; and the popular &lt;strong&gt;Visual Studio Code&lt;/strong&gt; can be made to work with CL using &lt;a href=&#34;https://github.com/cxxxr/cl-lsp&#34;&gt;cl-lsp&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We have an &lt;strong&gt;ipython-like REPL&lt;/strong&gt; (cl-repl),&lt;/li&gt;
&lt;li&gt;and for interactive notebooks, we have &lt;strong&gt;Jupyter kernels&lt;/strong&gt; and yet another
notebook (Darkmatter).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A very welcome improvement is the Common Lisp fundation&amp;rsquo;s website:
&lt;a href=&#34;https://common-lisp.net/&#34;&gt;https://common-lisp.net/&lt;/a&gt; It got a massive update and is now
attractive. We had &lt;a href=&#34;http://lisp-lang.org/&#34;&gt;http://lisp-lang.org/&lt;/a&gt; (don&amp;rsquo;t miss its success
stories section (did you know that pgloader was re-written from Python to CL ? :) )), but common-lisp.net was a googlers&amp;rsquo; honey pot.&lt;/p&gt;

&lt;p&gt;This website uses two &amp;ldquo;awesome&amp;rdquo; lists that were created or massively
furnished last year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome-CL&lt;/a&gt; list,
updated with hundreds of commits, which hopefully makes for a more
discoverable and appealing ecosystem, and&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies&#34;&gt;Awesome Lisp Companies&lt;/a&gt;:
it was needed because Lispers didn&amp;rsquo;t know a lot of companies using
CL appart from IRobot, Google&amp;rsquo;s ITA (powering
&lt;a href=&#34;http://kayak.com/&#34;&gt;Kayak&lt;/a&gt;, &lt;a href=&#34;http://orbitz.com/&#34;&gt;Orbitz&lt;/a&gt; and
others), Grammatech, YCombinator, Siscog or other dead ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other places to learn Common Lisp include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a9at82/clexercise_common_lisp_learning_system_running_on/&#34;&gt;cl-exercise: a Common Lisp Learning System running on browsers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;coding schools, like &lt;a href=&#34;https://open.kattis.com/help&#34;&gt;Kattis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and competitive Programming websites like CodeForces,
HackerEarth, HackerRank, and CodeChef.&lt;/li&gt;
&lt;li&gt;lastly, &lt;a href=&#34;https://github.com/norvig/paip-lisp&#34;&gt;Peter Norvig&amp;rsquo;s book Paradigms of Artificial Intelligence Programming is available on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also regularly have new screencasts to enjoy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a lot being from &lt;a href=&#34;https://github.com/cbaggers/&#34;&gt;Baggers&lt;/a&gt;: he does the following and he streams live nearly weekly

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/playlist?list=PL2VAYZE_4wRJi_vgpjsH75kMhN4KsuzR_&#34;&gt;little bits of Lisp&lt;/a&gt;: short videos to learn Lisp basics&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/results?search_query=lots+of+bits+of+lisp+&#34;&gt;lots of bits of Lisp&lt;/a&gt;: long videos to dive deep in advanced subjects (macros, CFFI,…)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=82o5NeyZtvw&amp;amp;list=PL2VAYZE_4wRITJBv6saaKouj4sWSG1FcS&#34;&gt;Pushing pixels with Lisp&lt;/a&gt;: mostly working with OpenGL&lt;/li&gt;
&lt;li&gt;and &lt;a href=&#34;https://www.youtube.com/user/CBaggers/playlists&#34;&gt;more&lt;/a&gt; !&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/playlist?list=PLkDl6Irujx9MtJPRRP5KBH40SGCenztPW&#34;&gt;Shinmera&lt;/a&gt;
has lots of videos too, we can see him working on game engines,
games, his libraries, Qt applications and more,&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://www.youtube.com/watch?v=z7V5BL6W3CA&#34;&gt;CL study group&lt;/a&gt; (here, an introduction to Screamer, a non-deterministic programming library)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;implementations&#34;&gt;Implementations&lt;/h1&gt;

&lt;p&gt;Time is good for Common Lisp implementations. Most date back from
decades and already proved what they can do (remember, SBCL is a
descendant of the Lisp that went to space). Hence the lack of hype,
IMO. Yet, many are in active development, and keep improving. As
&lt;code&gt;/u/defunkydrummer&lt;/code&gt; observed:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are lucky to live in a time where Lisp development is still ongoing, many teams carrying the flag of open-source Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SBCL (new release today)&lt;/li&gt;
&lt;li&gt;SICL (last commit 2 hours ago)&lt;/li&gt;
&lt;li&gt;ECL (last commit, yesterday),&lt;/li&gt;
&lt;li&gt;CLASP (last commit 2 days ago)&lt;/li&gt;
&lt;li&gt;CCL (last commit 7 days ago),&lt;/li&gt;
&lt;li&gt;CLISP (two weeks ago),&lt;/li&gt;
&lt;li&gt;CMUCL (1 month ago)&lt;/li&gt;
&lt;li&gt;ABCL (3 months ago)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;SBCL has monthly releases. If you read the release notes, you might worry:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the amount of changes in each release is decreasing these years&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;but, as &lt;code&gt;/u/baggers&lt;/code&gt; notes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think the commits tell a slightly different tale though. There is always a lot of background &amp;lsquo;making stuff better&amp;rsquo; work than won&amp;rsquo;t appear as the explanation would either be ultra internal and specific or would be super vague and very similar each month (for example &amp;lsquo;stuff is slightly faster&amp;rsquo;).&lt;/p&gt;

&lt;p&gt;For one that would be overly specific &lt;a href=&#34;https://github.com/sbcl/sbcl/commit/adc83086ff26c46e647b22d76fe22d57889b6ace&#34;&gt;this one&lt;/a&gt; might make for a good example. It&amp;rsquo;s grand work, but doesn&amp;rsquo;t surface in any specific lisp feature, stuff is just better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Furthermore, a maintainer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Or the developers are too lazy to describe their changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;which isn&amp;rsquo;t a good reason ;)&lt;/p&gt;

&lt;p&gt;We got a new release of Corman Lisp, a high performance Windows/32bit specific implementation with a built in IDE,&lt;/p&gt;

&lt;p&gt;we have CLASP, targetting C++ through LLVM (see &lt;a href=&#34;https://www.youtube.com/watch?v=mbdXeRBbgDM&amp;amp;app=desktop&#34;&gt;“Lessons Learned Implementing Common Lisp with LLVM”&lt;/a&gt;), built with the Cleavir compiler, part of SICL, a very
new implementation of Common Lisp with fresh ideas,&lt;/p&gt;

&lt;p&gt;we have ABCL targetting the JVM, Embedable Common Lisp, without
forgetting active commercial ones, like LispWorks and AllegroCL. While
I&amp;rsquo;m at it, you might want to have a look at
&lt;a href=&#34;https://wukix.com/mocl&#34;&gt;MOCL&lt;/a&gt; for IOs, Android and OSx.&lt;/p&gt;

&lt;p&gt;We got a nice talk by Clozure Common Lisp&amp;rsquo;s maintainer:
&lt;a href=&#34;http://thisoldlisp.com/&#34;&gt;this Old Lisp&lt;/a&gt; (this one may be the second
most used implementation, particularly good for development &amp;ndash; super fast
compilation times (I heard it compiles itself in seconds), &lt;a href=&#34;https://ccl.clozure.com/manual/chapter4.3.html#Advising&#34;&gt;advising&lt;/a&gt;, &lt;a href=&#34;https://ccl.clozure.com/manual/chapter4.12.html#watched-objects&#34;&gt;watched objects&lt;/a&gt;, its own &lt;a href=&#34;https://ccl.clozure.com/docs/ccl.html#the-clozure-cl-ide&#34;&gt;IDE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Last note, a SBCL maintainer started a RISC-V port: &lt;a href=&#34;http://christophe.rhodes.io/notes/blog/posts/2018/first_riscy_steps/&#34;&gt;First RISCy Steps &amp;ndash; Porting SBCL to the RISC-V&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So: welcome to this new world. It&amp;rsquo;s bigger than I thought, for sure.&lt;/p&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;p&gt;I only list some projects that can be of interest to anybody. For the full stuff see the quaterly posts !&lt;/p&gt;

&lt;!-- I fear that it would be seen as representative of the CL new tools and libraries.  --&gt;

&lt;h2 id=&#34;new-projects&#34;&gt;New projects&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a954yf/next_browser_120_is_out/&#34;&gt;Next browser 1.2.0 is out!&lt;/a&gt;: a browser exposing all its internals to CL. Be productive.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/r/drmeister/cando/&#34;&gt;CANDO - A Computational Chemistry programming environment integrating Common Lisp and C++ based on the Jupyter notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tarballs-are-good/coalton&#34;&gt;Coalton, a dialect of ML embedded in Common Lisp (alpha)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/terminal625/sucle&#34;&gt;Voxel game engine (Minecraft)&lt;/a&gt; - a Minecraft engine. Allows for interactive changes.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/emotiq/emotiq&#34;&gt;Emotiq - blockchain in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sjl.bitbucket.io/temperance/&#34;&gt;Temperance - logic programming (in development, reached v1.0.0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/rigetticomputing/magicl&#34;&gt;MAGICL: Matrix Algebra proGrams In Common Lisp - Rigetti Computing&lt;/a&gt; (quantum computing)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bradleyjensen/shcl&#34;&gt;SHCL: An Unholy Union of POSIX Shell and Common Lisp&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8kpbcz/shcl_an_unholy_union_of_posix_shell_and_common/&#34;&gt;reddit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jscl-project.github.io/&#34;&gt;JSCL 0.7.0 now supports CLOS thanks to the work of vlad-km&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;cl-torrents 0.9 - readline interface and 1337x.to scraper&#34;&gt;cl-torrents 0.9 - readline interface and 1337x.to scraper&lt;/a&gt; - a simple tool to search for torrents on popular trackers. My first CL app. Web and GUI interfaces in the making.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://vimeo.com/237947324&#34;&gt;Introducing Seed: An Interactive Software Environment in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/tovero/&#34;&gt;Tovero is a 3D modeling system for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/jgkamat/rmsbolt&#34;&gt;RMSBolt: See what your compiler is going inside of Emacs (has minimal support for Common Lisp)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.michaelfiano.com/projects/pngload/&#34;&gt;pngload: A PNG (Portable Network Graphics) image format decoder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9brkej/clvep_a_video_effects_processor/&#34;&gt;cl-vep: a video effects processor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tarballs-are-good/algebraic-data-library/&#34;&gt;algebraic-data-library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8f6wez/petalisp_elegant_high_performance_computing/&#34;&gt;Petalisp&lt;/a&gt;: Elegant High Performance Computing&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vseloved/wiki-lang-detect&#34;&gt;wiki-lang-detect&lt;/a&gt;: Text language identification using Wikipedia data&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/privet-kitty/dufy&#34;&gt;Dufy, a color library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8gzm4w/ppath_a_path_manipulation_library/&#34;&gt;ppath, a path manipulation library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://compbio.ucdenver.edu/Hunter_lab/Hunter/cl-statistics.lisp&#34;&gt;cl-statistics.lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/luksamuk/powerlisp&#34;&gt;Powerlisp: A simple tool to automate your work with dmenu/rofi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gschjetne/json-mop&#34;&gt;json-mop&lt;/a&gt;: A metaclass for bridging CLOS and JSON objects&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/obicons/clsh&#34;&gt;clsh&lt;/a&gt;: a set of Lispy bindings for running and composing *nix processes&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/pcostanza/filtered-functions&#34;&gt;filtered-functions&lt;/a&gt; - enables the use of arbitrary predicates for selecting and applying methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;web&#34;&gt;Web&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://40ants.com/weblocks/quickstart.html&#34;&gt;Weblocks&amp;rsquo; new quickstart&lt;/a&gt; -
Weblocks is an isomorphic web frameworks that allows to write
interactive web apps without writing Javascript (nor writing code that
transpiles to JS). It is seeing a massive update right now. Being Lisp,
we can build a self-contained executable of our web app, send it to
the server, run it and see it from the outside.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#email&#34;&gt;three email libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reddit-archive/reddit1.0&#34;&gt;reddit1.0 source code&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/886yeu/reddit10/&#34;&gt;comments&lt;/a&gt;), then &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8ata3c/reddit_code_runs_on_sbcl/&#34;&gt;Reddit&amp;rsquo;s code runs on SBCL&lt;/a&gt;. See also &lt;a href=&#34;https://www.reddit.com/r/programming/comments/883vzs/old_reddit_source_code/&#34;&gt;reddit&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.klipse.tech/lisp/2018/05/07/blog-common-lisp.html&#34;&gt;Interactive Common Lisp code snippets in any web page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Arboreta/arboreta-wasm&#34;&gt;arboreta-wasm - Common Lisp tooling for WebAssembly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For web libraries, see &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#network-and-internet&#34;&gt;https://github.com/CodyReichert/awesome-cl#network-and-internet&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;gui&#34;&gt;GUI&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://notabug.org/cage/nodgui&#34;&gt;nodgui - yet another Tcl/Tk-based GUI package for Common Lisp&lt;/a&gt; (based on Ltk, with syntax sugar and more meta-widgets)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/au0dmv/more_iup_gui_stuff/&#34;&gt;IUP bindings GUI stuff&lt;/a&gt; (in the works)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.ystok.ru/products/ywidgets/&#34;&gt;YstokWidgets Professional Edition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/~loliveira/ediware/midgets/doc/&#34;&gt;MIDGETS - A collection of CAPI widgets and utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/stacksmith/subtext&#34;&gt;subtext: A mostly-text-based UI bridges Common Lisp objects and runs of text. Minimal text-based user interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fjames86/ftw&#34;&gt;ftw: Common Lisp Win32 GUI library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plkrueger/CocoaInterface&#34;&gt;Cocoa interface code written in Lisp for use with Clozure Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/mcclim/posts/McCLIM-097-Imbolc-release.html&#34;&gt;McCLIM 0.9.7 &amp;ldquo;Imbolc&amp;rdquo; release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a31oxr/demo_sbcl_script_using_gtk/&#34;&gt;Demo SBCL script using Gtk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/defunkydrummer/abcl-jazz&#34;&gt;Demo ABCL script using Java Swing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;for GUI libraries: &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#gui&#34;&gt;https://github.com/CodyReichert/awesome-cl#gui&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;package-management&#34;&gt;Package management&lt;/h2&gt;

&lt;p&gt;Quicklisp is the de facto package manager, but new projects come to
complement it and bypass its limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://40ants.com/posts/Second-version-of-Ultralisporg-is-available-now.html&#34;&gt;the second version of Ultralisp is available&lt;/a&gt; - Ultralisp is an important project that fills a gap. It is a quicklisp distribution which updates every 5 minutes. It is also a Weblocks application!&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp.com.br/quicksys/&#34;&gt;quicksys&lt;/a&gt; - installs systems from multiple Quicklisp distributions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more options, see &lt;a href=&#34;https://github.com/fukamachi/qlot&#34;&gt;Qlot&lt;/a&gt; (install and pin libraries locally, like
Python&amp;rsquo;s virtualenv) and &lt;a href=&#34;https://github.com/roswell/roswell/&#34;&gt;Roswell&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;deployment&#34;&gt;Deployment&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apache/thrift/commits/master&#34;&gt;Apache Thrift gains CL support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hjudt/s2i-lisp&#34;&gt;s2i-lisp: Common Lisp + Quicklisp OpenShift Build Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fisxoj/lisp-images&#34;&gt;lisp-images: Docker images for common lisp development&lt;/a&gt; (with some others, see the awesome-list)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/r/eshamster/cl-devel2/&#34;&gt;A docker container for CL development&lt;/a&gt; (also &lt;a href=&#34;https://hub.docker.com/r/daewok/lisp-devel/&#34;&gt;lisp-devel&lt;/a&gt;, &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci&#34;&gt;CI on CL Cookbook&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/xh4/cube&#34;&gt;Kubernetes Client Library for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp&#34;&gt;Heroku buildpack for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/y2q-actionman/cl-aws-custom-runtime-test&#34;&gt;cl-aws-custom-runtime&lt;/a&gt; - An example of using Common Lisp (SBCL) as a custom runtime on AWS lambda.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/deadtrickster/prometheus.cl&#34;&gt;prometheus.cl&lt;/a&gt; - Prometheus.io client. Grafana dashboard for SBCL and Hunchentoot metrics (memory, threads, requests per second,…).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also deploy apps on Digital Ocean, and no need to say that
deploying a
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html#building-a-self-contained-executable&#34;&gt;self-contained executable&lt;/a&gt;
is easy,
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html#remote-debugging&#34;&gt;connecting to a remote instance&lt;/a&gt;
too.&lt;/p&gt;

&lt;h2 id=&#34;music&#34;&gt;Music&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/MegaLoler/Music&#34;&gt;Music: Music framework for musical expression in Common Lisp with a focus on music theory (built from scratch, on development)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://michaelgogins.tumblr.com/post/178126207468/composing-in-lisp&#34;&gt;Composing in Lisp with Csound&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/shuffletron-lisp-music-player-for-the-terminal/&#34;&gt;Shuffletron, a Common Lisp Music Player for the terminal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;see also &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#audio&#34;&gt;audio and music composition software&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;re-discoveries&#34;&gt;(re)Discoveries&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lmj/lfarm&#34;&gt;lfarm - a library for distributing work across machines (on top of lparallel and usocket)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nikodemus/screamer&#34;&gt;Screamer - nondeterministic programming. Augment Common Lisp with practically all of the functionality of both Prolog and constraint logic programming languages (10 yo, Nikodemus)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sellout/quid-pro-quo&#34;&gt;quid-pro-quo: a contract programming library in the style of Eiffel’s Design by Contract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7mji50/cells_spreadsheetlike_expressiveness_for_clos/&#34;&gt;Cells, spreadsheet-like expressiveness for CLOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mkoeppe/cl-bibtex&#34;&gt;cl-bibtex: A compatible re-implementation of the BibTeX program in Common Lisp, with a BST-to-CL compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/y2q-actionman/with-c-syntax&#34;&gt;C language syntax embedded in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.common-lisp.net/gendl/gendl&#34;&gt;gendl - Generative Programming and Knowledge-based Engineering (KBE) system embedded in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://cram-system.org/doc/ide&#34;&gt;Cognitive Robot Abstract Machine = Common Lisp + ROS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://scymtym.github.io/esrap/&#34;&gt;Esrap - a packrat parser for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7oaum4/cmera_a_commonlisp_sourcetosource_compiler_to/&#34;&gt;C-Mera, a Common Lisp source-to-source compiler to generate C/C++&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/882mz4/clbench_common_lisp_benchmarking_suite/&#34;&gt;cl-bench - Common Lisp benchmarking suite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://faculty.hampshire.edu/lspector/qgame.html&#34;&gt;QGAME: Quantum and Gate Measurement Emulator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;articles&#34;&gt;Articles&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/&#34;&gt;A Road to Common Lisp&lt;/a&gt; (&lt;a href=&#34;https://news.ycombinator.com/item?id=17852194&#34;&gt;hacker news comments&lt;/a&gt;). You should read this one.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5952920/&#34;&gt;How the strengths of Lisp-family languages facilitate building complex and flexible bioinformatics applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisper.in/nlp-date-parser&#34;&gt;Writing a natural language date and time parser - internals of the Common Lisp library Chronicity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.darkchestnut.com/2018/hunchentoot_custom_sessions/&#34;&gt;Implementing Hunchentoot custom sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/overview-of-documentation-generators/&#34;&gt;Overview of Documentation Generators (codex, coo, declt, staple, cldomain)&lt;/a&gt;
&lt;!-- - [Challenging myself to learn Common Lisp in one month](https://github.com/TomLisankie/Learning-Lisp) --&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fourier.github.io/lisp/2019/01/02/reflex-map.html&#34;&gt;Converter of maps from Reflex Arena to QuakeWorld. cl-yacc, 3d-matrices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://two-wrongs.com/debugging-common-lisp-in-slime.html&#34;&gt;Debugging Common Lisp in Slime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www-fourier.ujf-grenoble.fr/~sergerar/Papers/Packaging.pdf&#34;&gt;Packages in Common Lisp, a tutorial (pdf)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.darkchestnut.com/2018/how-to-write-5am-test-fixtures/&#34;&gt;How to write test fixtures for FiveAM - Dark Chestnut&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://allegrograph.com/franz-and-semantic-web-company-partner-to-create-a-noam-chomsky-knowledge-graph/&#34;&gt;Franz and Semantic Web Co. Partner to Create a Noam Chomsky Knowledge Graph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://notes.eatonphil.com/compiler-basics-lisp-to-assembly.html&#34;&gt;Compiler basics: lisp to assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.webofstories.com/play/marvin.minsky/44&#34;&gt;Marvin Minsky - Scientist - The beauty of the Lisp language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.newresalhaider.com/post/common-treasure/&#34;&gt;Excavating a Common Treasure: Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/07/fun-with-macros-if-let/&#34;&gt;Fun with Macros: If-Let and When-Let / Steve Losh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://openresearch-repository.anu.edu.au/bitstream/1885/144603/1/Sorensen%20Thesis%202018.pdf&#34;&gt;Extempore - The design, implementation and application of a cyber-physical programming language, Andrew Sorensen, Thesis, 2018 (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://m00natic.github.io/lisp/manual-jit.html&#34;&gt;Uniform Structured Syntax, Metaprogramming and Run-time Compilation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://z0ltan.wordpress.com/2018/08/04/simple-expression-evaluator-comparison-between-haskell-rust-and-common-lisp/&#34;&gt;Simple expression evaluator comparison between Haskell, Rust, and Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/98s5zp/lisping_at_jpl/&#34;&gt;Lisping at JPL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and also&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8bshzw/lisp_jazz_aikido_three_expressions_of_a_single/&#34;&gt;Lisp, Jazz, Aikido: Three Expressions of a Single Essence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://biolisp.github.io/#why-lisp&#34;&gt;Why lisp - biolisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/05/fun-with-macros-gathering/&#34;&gt;Fun with Macros: Gathering / Steve Losh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://can3p.github.io/blog/2018/06/19/client-writeup-intro/&#34;&gt;Experience writing a full featured livejournal blog client in Common Lisp&lt;/a&gt;. Part 2: &lt;a href=&#34;http://can3p.github.io/blog/2018/06/22/client-writeup-logic/&#34;&gt;client logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8o2c1y/the_uncommon_lisp_approach_to_operations_research/&#34;&gt;The (Un)common Lisp approach to Operations Research (2012)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8jq465/alien_return_of_alien_technology_to_classical/&#34;&gt;Alien: Return of Alien Technology to Classical Planning &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.teknik.io/phoe/p/1633&#34;&gt;Emacs + ECL on Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/&#34;&gt;Generic, consistent and dotted access of data structures with Access - lisp-journey&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7pysmx/generic_consistent_and_dotted_access_of_data/&#34;&gt;reddit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@MartinCracauer/llvms-garbage-collection-facilities-and-sbcl-s-generational-gc-a13eedfb1b31&#34;&gt;LLVM’s garbage collection facilities and SBCL’s generational GC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/snippets-functional-style-more/&#34;&gt;A bunch of utilities from (again) sjl: higher order functions, sequences, debugging, profiling.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://langnostic.inaimathi.ca/posts/the-return-of-cl-notebook&#34;&gt;The return of cl-notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7rsfyn/testing_the_series_common_lisp_package/&#34;&gt;Testing the SERIES package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On games:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://reader.tymoon.eu/article/370&#34;&gt;About Making Games in Lisp - Gamedev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://defungames.com/2018/12/creating-a-non-trivial-lisp-game-in-2018/&#34;&gt;Creating a (Non-Trivial) Lisp Game in 2018&lt;/a&gt; (they just launched a &lt;a href=&#34;https://www.kickstarter.com/projects/defungames/spycursion-hacking-espionage-edutainment-mmo&#34;&gt;Crowdfunding&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://old.reddit.com/r/Common_Lisp/comments/93g3p2/a_story_of_defun_games/&#34;&gt;A Story of (defun games ())&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lthms.xyz/blog/lisp-journey-getting-started&#34;&gt;Getting Started With trivial-gamekit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;other-screencasts&#34;&gt;Other screencasts&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=dw-y3vNDRWk&#34;&gt;Lisp, The Quantum Programmer&amp;rsquo;s Choice - Computerphile episode 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=9VIT_Ml2v-Q&#34;&gt;McCLIM + Maxima: plot manipulation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=AvC82EjoPYU&#34;&gt;McCLIM + Maxima: vector demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=CbfHpLUPL7E&#34;&gt;Comfy Lisp Programming - Project &amp;ldquo;Wikify&amp;rdquo; | Episode 2 @ 10am PST &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8ubnkn/common_lisp_and_c17_live_coding_stream_tinycdn/&#34;&gt;Common lisp and C++17 Live coding stream | TinyCDN CFFI Interop | Episode 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=XT7JYPtWMd8&#34;&gt;Growing a Lisp compiler - Amsterdam Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=bl8jQ2wRh6k&#34;&gt;Web Development in Emacs, Common Lisp and Clojurescript - Potato (Slack-like)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;discussion&#34;&gt;Discussion&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a7156w/lisp_and_the_remote_agent/&#34;&gt;Lisp and the remote agent - aka Lisp in a spacecraft - with an AMA of Ron Garret&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a5ggd4/how_to_make_common_lisp_popular/&#34;&gt;How to make (Common) Lisp popular?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9r9xy6/feedback_from_a_new_lispworks_user/&#34;&gt;Feedback from a new LispWorks user&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9qh3op/how_is_lispworks_the_company_doing/&#34;&gt;how is LispWorks the company going ?&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/a3r4hb/how_do_you_normally_use_a_program_once_written/&#34;&gt;How do you normally use a program once written ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a10629/structs_vs_parametric_polymorphism_an_answer_to/&#34;&gt;Structs vs Parametric Polymorphism (an answer to the &amp;ldquo;switching from Common Lisp to Julia - thoughts ?&amp;rdquo; post)&lt;/a&gt; also &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9y425b/switching_from_common_lisp_to_julia_your_thoughts/&#34;&gt;this discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9os171/how_to_work_on_a_project_and_make_sure/&#34;&gt;How to work on a project and make sure dependencies are tracked correctly?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a2hkq0/does_anyone_else_hate_loop_cl/&#34;&gt;Does anyone else hate LOOP?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9xd4gy/what_does_it_take_to_understand_the_true_power_of/&#34;&gt;What does it take to understand the true power of Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9qfrxe/how_lisp_made_your_life_easier/&#34;&gt;How did Lisp make your life easier ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9zpts4/should_local_variables_be_avoided_when_possible/&#34;&gt;Should local variables be avoided when possible when doing functional programming?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9upt86/abcl/&#34;&gt;Is ABCL an active project and does it support JRE 1.11?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9q68y8/has_the_gnu_coreutils_ever_been_implemented_in/&#34;&gt;Has the Gnu Coreutils ever been implemented in Lisp? If not, would that be a worthwhile project?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8bn7f9/common_lisp_and_machine_learning_these_days/&#34;&gt;Common Lisp and Machine Learning these days&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7z7wuq/has_anyone_considered_or_started_a_project_to/&#34;&gt;Has anyone considered or started a project to write a CL implementation in WebAssembly?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7s53qi/what_do_you_recommend_to_work_with_sql_databases/&#34;&gt;What do you recommend to work with SQL databases ? What&amp;rsquo;s your experience with Mito ?&lt;/a&gt; and &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7ozdcf/sqliteonly_interface_clsqlite_or_cldbi/&#34;&gt;sqlite only interface: cl-sqlite or cl-dbi ?&lt;/a&gt;
and &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7iebty/ask_rlisp_is_there_any_lightweight_orm_that/&#34;&gt;is there an ORM that generates classes from table definitions ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;learning-lisp&#34;&gt;Learning Lisp&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9er4mo/i_want_to_try_lisp_how_should_i_begin/&#34;&gt;I want to try Lisp, how should I begin?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9b7v56/what_lisp_dialect_for_real_world_applications/&#34;&gt;What lisp dialect for &amp;ldquo;real world&amp;rdquo; applications?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8w8cr1/what_do_commercial_lisps_offer_that_frees_dont/&#34;&gt;What do commercial Lisps offer that frees don&amp;rsquo;t?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9kiji7/which_nonclojure_lisp_to_learn_first/&#34;&gt;Which (non-Clojure) Lisp to learn first?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9k2vmi/can_cl_implement_clojures_keyword_as_function/&#34;&gt;Can CL implement Clojure&amp;rsquo;s keyword as function syntax?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8jzpzw/why_did_you_decide_to_learn_lisp/&#34;&gt;Why did you decide to learn Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8j9ing/how_do_you_go_about_starting_a_common_lisp/&#34;&gt;How do you go about starting a Common Lisp Project? A beginner looking for pointers.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/86ze0t/as_a_newbie_what_i_will_miss_if_i_choose_racket/&#34;&gt;As a newbie, what I will miss if I choose Racket over Common Lisp? Or if I happen to learn both at somepoint in future, choosing Racket/Common Lisp now would make sense?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7lf149/what_can_other_languages_do_that_lisp_cant/&#34;&gt;What can other languages do that Lisp can&amp;rsquo;t ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;common-lisp-vs&#34;&gt;Common Lisp VS &amp;hellip;&lt;/h2&gt;

&lt;!-- not sure if listing some of those is constructive, really; and the Clojure vs Common Lisp wars are getting really tiring...  and this coming from an active flamer (defunkydrummer) --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/ac9mm9/how_common_lisp_community_survived_without_the/&#34;&gt;How did the Common Lisp community survived without the equivalent of clojure.spec ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8wdw2r/is_there_a_lisp_that_is_considered_excellent/&#34;&gt;Is there a Lisp that is considered &amp;ldquo;excellent&amp;rdquo; about error handling ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9lhbnx/lisp_dialect_survey/&#34;&gt;Lisp Dialect survey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9i5mmp/the_julia_challenge/&#34;&gt;the Julia challenge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9g07to/python_pitfalls/&#34;&gt;Python pitfalls ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9lpssp/how_a_common_lisp_programmer_views_users_of_other/&#34;&gt;How a Common Lisp programmer views users of other languages (humor)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://med.miami.edu/news/miller-school-researchers-help-push-the-limits-of-programming-languages-in-&#34;&gt;Miller School Researchers Help Push the Limits of Programming Languages in Biology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8mcts3/lisp_vs_java_thought_you_guys_might_find_this/&#34;&gt;Lisp vs Java (thought you guys might find this humorous)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8q6gaa/what_other_languages_besides_lisp_do_you_enjoy/&#34;&gt;What other languages besides Lisp do you enjoy programming in?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Enjoy the material, and see you soon !&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;thanks to &lt;code&gt;/u/defunkydrummer&lt;/code&gt; for proofreading.&lt;/p&gt;

&lt;p&gt;fix or improve this article &lt;a href=&#34;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/issues&#34;&gt;on Gitlab&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Gray streams</title>
      <link>/gray-streams/</link>
      <pubDate>Tue, 22 Jan 2019 07:51:49 +0100</pubDate>
      
      <guid>/gray-streams/</guid>
      <description>

&lt;p&gt;This is a copy of &lt;a href=&#34;http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html&#34;&gt;http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html&lt;/a&gt; with syntax highlighting.&lt;/p&gt;

&lt;p&gt;FAILED Issue STREAM-DEFINITION-BY-USER (&amp;ldquo;Gray Streams&amp;rdquo;)&lt;/p&gt;

&lt;p&gt;This is the writeup of failed issue STREAM-DEFINITION-BY-USER. Because it did not pass, it has no official standing other than as a historical document.&lt;/p&gt;

&lt;p&gt;NOTES:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Several vendors have implemented this proposal anyway, so if you&amp;rsquo;d like to use this facility, you might check to see if it&amp;rsquo;s available in your implementation of choice in spite of not being part the &amp;ldquo;official&amp;rdquo; standard.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The facility described here is commonly referred to as &amp;ldquo;Gray Streams&amp;rdquo;, after David Gray, who wrote the proposal—please do not write this as &amp;ldquo;Grey Streams&amp;rdquo;!&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Another facility of note that came later and may be available in some implementations is Franz&amp;rsquo;s &amp;ldquo;Simple Streams&amp;rdquo;. It is newer and addresses a broader range of issues, but its availability in this or that implementation may be different.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&#34;http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user-notes.html&#34;&gt;Click here to see my personal notes on this issue.&lt;/a&gt;
&amp;ndash;Kent Pitman (10-Mar-2001)&lt;/p&gt;

&lt;p&gt;Issue:      STREAM-DEFINITION-BY-USER&lt;/p&gt;

&lt;p&gt;References: CLtL pages 329-332, 378-381, and 384-385.&lt;/p&gt;

&lt;p&gt;Related issues: STREAM-INFO, CLOSED-STREAM-FUNCTIONS, STREAM-ACCESS,
        STREAM-CAPABILITIES&lt;/p&gt;

&lt;p&gt;Category:   ADDITION&lt;/p&gt;

&lt;p&gt;Edit history:   Version 1, 22-Mar-89 by David N. Gray&lt;/p&gt;

&lt;p&gt;Status:     For discussion and evaluation; not proposed for
        inclusion in the standard at this time.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#problem-description&#34;&gt;Problem description&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#proposal-stream-definition-by-usergeneric-functions&#34;&gt;Proposal &lt;code&gt;stream-definition-by-user:generic-functions&lt;/code&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#overview&#34;&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#character-input&#34;&gt;Character input:&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#character-output&#34;&gt;Character output&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rationale&#34;&gt;Rationale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#current-practice&#34;&gt;Current practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#examples&#34;&gt;Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cost-to-implementors&#34;&gt;Cost to Implementors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cost-to-users&#34;&gt;Cost to Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cost-of-non-adoption&#34;&gt;Cost of non-adoption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#performance-impact&#34;&gt;Performance impact&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#benefits&#34;&gt;Benefits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#esthetics&#34;&gt;Esthetics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#discussion&#34;&gt;Discussion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;problem-description&#34;&gt;Problem description&lt;/h1&gt;

&lt;p&gt;Common Lisp does not provide a standard way for users to define their
  own streams for use by the standard I/O functions.  This impedes the
  development of window systems for Common Lisp because, while there are
  standard Common Lisp I/O functions and there are beginning to be
  standard window systems, there is no portable way to connect them
  together to make a portable Common Lisp window system.&lt;/p&gt;

&lt;p&gt;There are also many applications where users might want to define
  their own filter streams for doing things like printer device control,
  report formatting, character code translation, or
  encryption/decryption.&lt;/p&gt;

&lt;h1 id=&#34;proposal-stream-definition-by-user-generic-functions&#34;&gt;Proposal &lt;code&gt;stream-definition-by-user:generic-functions&lt;/code&gt;&lt;/h1&gt;

&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;

&lt;p&gt;Define a set of generic functions for performing I/O.  These functions
  will have methods that specialize on the stream argument; they would
  be used by the existing I/O functions.  Users could write additional
  methods for them in order to support their own stream classes.&lt;/p&gt;

&lt;p&gt;Define a set of classes to be used as the superclass of a stream class
  in order to provide some default methods.&lt;/p&gt;

&lt;p&gt;## Classes&lt;/p&gt;

&lt;p&gt;The following classes are to be used as super classes of user-defined
  stream classes.  They are not intended to be directly instantiated; they
  just provide places to hang default methods.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fundamental-stream&lt;/code&gt;              [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This class is a subclass of `stream` and of `standard-object`.  `streamp`
will return true for an instance of any class that includes this.  (It
may return true for some other things also.)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-input-stream&lt;/code&gt;            [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A subclass of `fundamental-stream`.  Its inclusion causes `input-stream-p`
to return true.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-output-stream&lt;/code&gt;           [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A subclass of `fundamental-stream`.  Its inclusion causes `output-stream-p`
to return true.  Bi-direction streams may be formed by including both
`fundamental-output-stream` and `fundamental-input-stream`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-character-stream&lt;/code&gt;            [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A subclass of `fundamental-stream`.  It provides a method for
`stream-element-type` which returns `character`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-binary-stream&lt;/code&gt;           [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A subclass of `fundamental-stream`.  Any instantiable class that
includes this needs to define a method for `stream-element-type`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-character-input-stream&lt;/code&gt;      [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Includes `fundamental-input-stream` and `fundamental-character-stream`.
It provides default methods for several generic functions used for
character input.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-character-output-stream&lt;/code&gt;     [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Includes `fundamental-output-stream` and `fundamental-character-stream`.
It provides default methods for several generic functions used for
character output.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-binary-input-stream&lt;/code&gt;     [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Includes `fundamental-input-stream` and `fundamental-binary-stream`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;fundamental-binary-output-stream&lt;/code&gt;        [Class]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Includes `fundamental-output-stream` and `fundamental-binary-stream`.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;character-input&#34;&gt;Character input&lt;/h2&gt;

&lt;p&gt;A character input stream can be created by defining a class that
  includes &lt;code&gt;fundamental-character-input-stream&lt;/code&gt; and defining methods for the
  generic functions below.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stream-read-char&lt;/code&gt;  stream            [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This reads one character from the stream.  It returns either a
character object, or the symbol :EOF if the stream is at end-of-file.
Every subclass of `fundamental-character-input-stream` must define a
method for this function.

Note that for all of these generic functions, the stream argument
must be a stream object, not T or NIL.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-unread-char&lt;/code&gt;  stream  character       [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Un-does the last call to `stream-read-char`, as in `unread-char`.  Returns
NIL.  Every subclass of `fundamental-character-input-stream` must define
a method for this function.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-read-char-no-hang&lt;/code&gt;  stream        [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This is used to implement `read-char-no-hang`.  It returns either a
character, or NIL if no input is currently available, or :EOF if
end-of-file is reached.  The default method provided by
`fundamental-character-input-stream` simply calls `stream-read-char`; this
is sufficient for file streams, but interactive streams should define
their own method.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-peek-char&lt;/code&gt;  stream            [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Used to implement `peek-char`; this corresponds to peek-type of NIL.
It returns either a character or :EOF.  The default method
calls `stream-read-char` and `stream-unread-char`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-listen&lt;/code&gt;  stream               [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Used by `listen`.  Returns true or false.  The default method uses
`stream-read-char-no-hang` and `stream-unread-char`.  Most streams should
define their own method since it will usually be trivial and will
always be more efficient than the default method.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-read-line&lt;/code&gt;  stream            [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Used by `read-line`.  A string is returned as the first value.  The
second value is true if the string was terminated by end-of-file
instead of the end of a line.  The default method uses repeated
calls to `stream-read-char`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-clear-input&lt;/code&gt;  stream          [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Implements `clear-input` for the stream, returning NIL.  The default
method does nothing.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;character-output&#34;&gt;Character output&lt;/h2&gt;

&lt;p&gt;A character output stream can be created by defining a class that
  includes &lt;code&gt;fundamental-character-output-stream&lt;/code&gt; and defining methods for the
  generic functions below.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stream-write-char&lt;/code&gt;  stream character     [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Writes character to the stream and returns the character.  Every
subclass of `fundamental-character-output-stream` must have a method
defined for this function.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-line-column&lt;/code&gt;  stream          [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This function returns the column number where the next character
will be written, or NIL if that is not meaningful for this stream.
The first column on a line is numbered 0.  This function is used in
the implementation of `pprint` and the FORMAT ~T directive.  For every
character output stream class that is defined, a method must be
defined for this function, although it is permissible for it to
always return NIL.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-start-line-p&lt;/code&gt;  stream         [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This is a predicate which returns T if the stream is positioned at the
beginning of a line, else NIL.  It is permissible to always return
NIL.  This is used in the implementation of `fresh-line`.  Note that
while a value of 0 from `stream-line-column` also indicates the
beginning of a line, there are cases where `stream-start-line-p` can be
meaningfully implemented although `stream-line-column` can&#39;t be.  For
example, for a window using variable-width characters, the column
number isn&#39;t very meaningful, but the beginning of the line does have
a clear meaning.  The default method for `stream-start-line-p` on class
`fundamental-character-output-stream` uses `stream-line-column`, so if
that is defined to return `nil`, then a method should be provided for
either `stream-start-line-p` or `stream-fresh-line`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-write-string&lt;/code&gt; stream string &amp;amp;optional start end [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This is used by `write-string`.  It writes the string to the stream,
optionally delimited by start and end, which default to 0 and NIL.
The string argument is returned.  The default method provided by
`fundamental-character-output-stream` uses repeated calls to
`stream-write-char`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-terpri&lt;/code&gt;  stream               [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Writes an end of line, as for `terpri`.  Returns NIL.  The default
method does (`stream-write-char` stream #\NEWLINE).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-fresh-line&lt;/code&gt;  stream           [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Used by `fresh-line`.  The default method uses `stream-start-line-p` and
`stream-terpri`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-finish-output&lt;/code&gt;  stream            [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Implements `finish-output`.  The default method does nothing.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-force-output&lt;/code&gt;  stream         [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Implements `force-output`.  The default method does nothing.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-clear-output&lt;/code&gt;  stream         [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Implements `clear-output`.  The default method does nothing.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-advance-to-column&lt;/code&gt;  stream column [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Writes enough blank space so that the next character will be written
at the specified column.  Returns true if the operation is
successful, or NIL if it is not supported for this stream.
This is intended for use by by `pprint` and FORMAT ~T.  The default
method uses `stream-line-column` and repeated calls to
`stream-write-char` with a #\SPACE character; it returns NIL if
`stream-line-column` returns NIL.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;## Other functions&lt;/p&gt;

&lt;p&gt;&lt;code&gt;close&lt;/code&gt;  stream &amp;amp;key abort            [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;The existing function `close` is redefined to be a generic function, but
otherwise behaves the same.  The default method provided by class
`fundamental-stream` sets a flag for `open-stream-p`.  The value returned
by `close` will be as specified by the issue `closed-stream-operations`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;open-stream-p&lt;/code&gt; stream                [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This function [from proposal `stream-access]` is made generic.  A
default method is provided by class `fundamental-stream` which returns
true if `close` has not been called on the stream.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;streamp&lt;/code&gt;  object             [Generic Function]&lt;/p&gt;

&lt;p&gt;&lt;code&gt;input-stream-p&lt;/code&gt;  stream          [Generic Function]&lt;/p&gt;

&lt;p&gt;&lt;code&gt;output-stream-p&lt;/code&gt;  stream         [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;These three existing predicates may optionally be implemented as
generic functions for implementations that want to permit users to
define streams that are not `standard-object`s.  Normally, the default
methods provided by classes `fundamental-input-stream` and
`fundamental-output-stream` are sufficient.  Note that, for example,
(INPUT-STREAM-P x) is not equivalent to (TYPEP x
&#39;FUNDAMENTAL-INPUT-STREAM) because implementations may have
additional ways of defining their own streams even if they don&#39;t
make that visible by making these predicates generic.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-element-type&lt;/code&gt;  stream         [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;This existing function is made generic, but otherwise behaves the
same.  Class `fundamental-character-stream` provides a default method
which returns `character`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;pathname&lt;/code&gt; and &lt;code&gt;truename&lt;/code&gt; are also permitted to be implemented as generic
  functions.  There is no default method since these are not valid for
  all streams.&lt;/p&gt;

&lt;p&gt;## Binary streams:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Binary streams can be created by defining a class that includes either
`fundamental-binary-input-stream` or `fundamental-binary-output-stream`
(or both) and defining a method for `stream-element-type` and for one or
both of the following generic functions.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-read-byte&lt;/code&gt;  stream            [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Used by `read-byte`; returns either an integer, or the symbol :EOF if the
stream is at end-of-file.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stream-write-byte&lt;/code&gt; stream integer        [Generic Function]&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Implements `write-byte`; writes the integer to the stream and returns
the integer as the result.
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;rationale&#34;&gt;Rationale&lt;/h1&gt;

&lt;p&gt;The existing I/O functions cannot be made generic because, in nearly
  every case, the stream argument is optional, and therefore cannot be
  specialized.  Therefore, it is necessary to define a lower-level
  generic function to be used by the existing function.  It also isn&amp;rsquo;t
  appropriate to specialize on the second argument of &lt;code&gt;print-object&lt;/code&gt; because
  it is a higher-level function &amp;ndash; even when the first argument is a
  character or a string, it needs to format it in accordance with
  &lt;code&gt;*PRINT-ESCAPE*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to make the meaning as obvious as possible, the names of the
  generic functions have been formed by prefixing &amp;ldquo;&lt;code&gt;stream-&lt;/code&gt;&amp;rdquo; to the
  corresponding non-generic function.&lt;/p&gt;

&lt;p&gt;Having the generic input functions just return :EOF at end-of-file, with
  the higher-level functions handling the eof-error-p and eof-value
  arguments, simplifies the generic function interface and makes it more
  efficient by not needing to pass through those arguments.  Note that the
  functions that use this convention can only return a character or
  integer as a stream element, so there is no possibility of ambiguity.&lt;/p&gt;

&lt;p&gt;Functions &lt;code&gt;stream-line-column&lt;/code&gt;, &lt;code&gt;stream-start-line-p&lt;/code&gt;, and
  &lt;code&gt;stream-advance-to-column&lt;/code&gt; may appear to be a reincarnation of the
  defeated proposal &lt;code&gt;stream-info&lt;/code&gt;, but the motivation here is different.
  This interface needs to be defined if user-defined streams are to be
  able to be used by &lt;code&gt;pprint&lt;/code&gt; and FORMAT ~T, which could be viewed as a
  separate question from whether the user can call then on
  system-defined streams.&lt;/p&gt;

&lt;h1 id=&#34;current-practice&#34;&gt;Current practice&lt;/h1&gt;

&lt;p&gt;No one currently supports exactly this proposal, but this is very
  similar to the stream interface used in &lt;code&gt;clue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On descendants of the MIT Lisp Machine, streams can be implemented
  by users as either flavors, with methods to accept the various
  messages corresponding to the I/O operations, or as functions, which
  take a message keyword as their first argument.&lt;/p&gt;

&lt;h1 id=&#34;examples&#34;&gt;Examples&lt;/h1&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  ;;;; Here is an example of how the default methods could be
  ;;;; implemented (omitting the most trivial ones):

  (defmethod STREAM-PEEK-CHAR ((stream fundamental-character-input-stream))
    (let ((character (stream-read-char stream)))
      (unless (eq character :eof)
	(stream-unread-char stream character))
      character))

  (defmethod STREAM-LISTEN ((stream fundamental-character-input-stream))
    (let ((char (stream-read-char-no-hang stream)))
      (and (not (null char))
	   (not (eq char :eof))
	   (progn (stream-unread-char stream char) t))))

  (defmethod STREAM-READ-LINE ((stream fundamental-character-input-stream))
    (let ((line (make-array 64 :element-type &#39;string-char
			    :fill-pointer 0 :adjustable t)))
      (loop (let ((character (stream-read-char stream)))
	      (if (eq character :eof)
		  (return (values line t))
		(if (eql character #\newline)
		    (return (values line nil))
		  (vector-push-extend character line)))))))

  (defmethod STREAM-START-LINE-P ((stream fundamental-character-output-stream))
    (equal (stream-line-column stream) 0))

  (defmethod STREAM-WRITE-STRING ((stream fundamental-character-output-stream)
				  string &amp;amp;optional (start 0)
				  (end (length string)))
    (do ((i start (1+ i)))
	((&amp;gt;= i end) string)
      (stream-write-char stream (char string i))))

  (defmethod STREAM-TERPRI ((stream fundamental-character-output-stream))
    (stream-write-char stream #\newline)
    nil)

  (defmethod STREAM-FRESH-LINE ((stream fundamental-character-output-stream))
    (if (stream-start-line-p stream)
	nil
      (progn (stream-terpri stream) t)))

  (defmethod STREAM-ADVANCE-TO-COLUMN ((stream fundamental-character-output-stream)
				       column)
    (let ((current (stream-line-column stream)))
      (unless (null current)
	(dotimes (i (- current column) t)
	  (stream-write-char stream #\space)))))

  (defmethod INPUT-STREAM-P ((stream fundamental-input-stream)) t)
  (defmethod INPUT-STREAM-P ((stream fundamental-output-stream))
    ;; allow the two classes to be mixed in either order
    (typep stream &#39;fundamental-input-stream))
  (defmethod OUTPUT-STREAM-P ((stream fundamental-output-stream)) t)
  (defmethod OUTPUT-STREAM-P ((stream fundamental-input-stream))
    (typep stream &#39;fundamental-output-stream))

  ;;;; Following is an example of how the existing I/O functions could
  ;;;; be implemented using standard Common Lisp and the generic
  ;;;; functions specified above.  The standard functions being defined
  ;;;; are in upper case.

  ;;  Internal helper functions

  (proclaim &#39;(inline decode-read-arg decode-print-arg check-for-eof))
  (defun decode-read-arg (arg)
    (cond ((null arg) *standard-input*)
	  ((eq arg t) *terminal-io*)
	  (t arg)))

  (defun decode-print-arg (arg)
    (cond ((null arg) *standard-output*)
	  ((eq arg t) *terminal-io*)
	  (t arg)))

  (defun check-for-eof (value stream eof-errorp eof-value)
    (if (eq value :eof)
	(report-eof stream eof-errorp eof-value)
      value))

  (defun report-eof (stream eof-errorp eof-value)
    (if eof-errorp
	(error &#39;end-of-file :stream stream)
      eof-value))

  ;;;  Common Lisp input functions

  (defun READ-CHAR (&amp;amp;optional input-stream (eof-errorp t) eof-value recursive-p)
    (declare (ignore recursive-p)) ; a mistake in CLtL?
    (let ((stream (decode-read-arg input-stream)))
      (check-for-eof (stream-read-char stream) stream eof-errorp eof-value)))

  (defun PEEK-CHAR (&amp;amp;optional peek-type input-stream (eof-errorp t)
			eof-value recursive-p)
    (declare (ignore recursive-p))
    (let ((stream (decode-read-arg input-stream)))
      (if (null peek-type)
	  (check-for-eof (stream-peek-char stream) stream eof-errorp eof-value)
        (loop
	  (let ((value (stream-peek-char stream)))
	    (if (eq value :eof)
		(return (report-eof stream eof-errorp eof-value))
	      (if (if (eq peek-type t)
		      (not (member value &#39;(#\space #\tab #\newline
					   #\page #\return #\linefeed)))
		    (char= peek-type value))
		  (return value)
		(stream-read-char stream))))))))

  (defun UNREAD-CHAR (character &amp;amp;optional input-stream)
    (stream-unread-char (decode-read-arg input-stream) character))

  (defun LISTEN (&amp;amp;optional input-stream)
    (stream-listen (decode-read-arg input-stream)))

  (defun READ-LINE (&amp;amp;optional input-stream (eof-error-p t)
			eof-value recursive-p)
    (declare (ignore recursive-p))
    (let ((stream (decode-read-arg input-stream)))
      (multiple-value-bind (string eofp)
	  (stream-read-line stream)
	(if eofp
	    (if (= (length string) 0)
		(report-eof stream eof-error-p eof-value)
	      (values string t))
	  (values string nil)))))

  (defun CLEAR-INPUT (&amp;amp;optional input-stream)
    (stream-clear-input (decode-read-arg input-stream)))

  (defun READ-CHAR-NO-HANG (&amp;amp;optional input-stream (eof-errorp t)
				eof-value recursive-p)
    (declare (ignore recursive-p))
    (let ((stream (decode-read-arg input-stream)))
      (check-for-eof (stream-read-char-no-hang stream)
		     stream eof-errorp eof-value)))

  ;;;  Common Lisp output functions

  (defun WRITE-CHAR (character &amp;amp;optional output-stream)
     (stream-write-char (decode-print-arg output-stream) character))

  (defun FRESH-LINE (&amp;amp;optional output-stream)
    (stream-fresh-line (decode-print-arg output-stream)))

  (defun TERPRI (&amp;amp;optional output-stream)
    (stream-terpri (decode-print-arg output-stream)))

  (defun WRITE-STRING (string &amp;amp;optional output-stream &amp;amp;key (start 0) end)
    (stream-write-string (decode-print-arg output-stream) string start end))

  (defun WRITE-LINE (string &amp;amp;optional output-stream &amp;amp;key (start 0) end)
    (let ((stream (decode-print-arg output-stream)))
      (stream-write-string stream string start end)
      (stream-terpri stream)
      string))

  (defun FORCE-OUTPUT (&amp;amp;optional stream)
    (stream-force-output (decode-print-arg stream)))

  (defun FINISH-OUTPUT (&amp;amp;optional stream)
    (stream-finish-output (decode-print-arg stream)))

  (defun CLEAR-OUTPUT (&amp;amp;optional stream)
    (stream-clear-output (decode-print-arg stream)))

  ;;;  Binary streams

  (defun READ-BYTE (binary-input-stream &amp;amp;optional (eof-errorp t) eof-value)
    (check-for-eof (stream-read-byte binary-input-stream)
		   binary-input-stream eof-errorp eof-value))

  (defun WRITE-BYTE (integer binary-output-stream)
    (stream-write-byte binary-output-stream integer))

  ;;;  String streams

  (defclass string-input-stream (fundamental-character-input-stream)
    ((string :initarg :string :type string)
     (index :initarg :start :type fixnum)
     (end :initarg :end :type fixnum)
     ))

  (defun MAKE-STRING-INPUT-STREAM (string &amp;amp;optional (start 0) end)
    (make-instance &#39;string-input-stream :string string
		   :start start :end (or end (length string))))

  (defmethod stream-read-char ((stream string-input-stream))
    (with-slots (index end string) stream
      (if (&amp;gt;= index end)
	  :eof
	(prog1 (char string index)
	       (incf index)))))

  (defmethod stream-unread-char ((stream string-input-stream) character)
    (with-slots (index end string) stream
      (decf index)
      (assert (eql (char string index) character))
      nil))

  (defmethod stream-read-line ((stream string-input-stream))
    (with-slots (index end string) stream
      (let* ((endline (position #\newline string :start index :end end))
	     (line (subseq string index endline)))
	(if endline
	    (progn (setq index (1+ endline))
		   (values line nil))
	  (progn (setq index end)
		 (values line t))))))

  (defclass string-output-stream (fundamental-character-output-stream)
    ((string :initform nil :initarg :string)))

  (defun MAKE-STRING-OUTPUT-STREAM ()
    (make-instance &#39;string-output-stream))

  (defun GET-OUTPUT-STREAM-STRING (stream)
    (with-slots (string) stream
      (if (null string)
	  &amp;quot;&amp;quot;
	(prog1 string (setq string nil)))))

  (defmethod stream-write-char ((stream string-output-stream) character)
    (with-slots (string) stream
      (when (null string)
	(setq string (make-array 64. :element-type &#39;string-char
				 :fill-pointer 0 :adjustable t)))
      (vector-push-extend character string)
      character))

  (defmethod stream-line-column ((stream string-output-stream))
    (with-slots (string) stream
      (if (null string)
	  0
	(let ((nx (position #\newline string :from-end t)))
	  (if (null nx)
	      (length string)
	    (- (length string) nx 1))
	  ))))
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;cost-to-implementors&#34;&gt;Cost to Implementors&lt;/h1&gt;

&lt;p&gt;Given that CLOS is supported, adding the above generic functions and
  methods is easy, since most of the code is included in the examples
  above.  The hard part would be re-writing existing I/O functionality in
  terms of methods on these new generic functions.  That could be
  simplified if methods can be defined to forward the operations to the
  old representation of streams.  For a new implementation, the cost could
  be zero since an approach similar to this would likely be used anyway.&lt;/p&gt;

&lt;h1 id=&#34;cost-to-users&#34;&gt;Cost to Users&lt;/h1&gt;

&lt;p&gt;None; this is an upward-compatible addition.   Users won&amp;rsquo;t even
  need to know anything about this unless they actually need this feature.&lt;/p&gt;

&lt;h1 id=&#34;cost-of-non-adoption&#34;&gt;Cost of non-adoption&lt;/h1&gt;

&lt;p&gt;Development of portable I/O extensions will be discouraged.&lt;/p&gt;

&lt;h1 id=&#34;performance-impact&#34;&gt;Performance impact&lt;/h1&gt;

&lt;p&gt;This shouldn&amp;rsquo;t affect performance of new implementations (assuming an
  efficient CLOS implementation), but it could slow down I/O if it were
  clumsily grafted on top of an existing implementation.&lt;/p&gt;

&lt;h1 id=&#34;benefits&#34;&gt;Benefits&lt;/h1&gt;

&lt;p&gt;A broader domain of programs that can be written portably.&lt;/p&gt;

&lt;h1 id=&#34;esthetics&#34;&gt;Esthetics&lt;/h1&gt;

&lt;p&gt;This seems to be a simple, straight-forward approach.&lt;/p&gt;

&lt;h1 id=&#34;discussion&#34;&gt;Discussion&lt;/h1&gt;

&lt;p&gt;This proposal incorporates suggestions made by several people in
  response to an earlier outline.  So far, no one has expressed opposition
  to the concept.  There are some differences of opinion about whether
  certain operations should have default methods or required methods:
  &lt;code&gt;stream-listen&lt;/code&gt;, &lt;code&gt;stream-read-char-no-hang&lt;/code&gt;, &lt;code&gt;stream-line-column&lt;/code&gt;,
  and &lt;code&gt;stream-start-line-p&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An experimental prototype of this has been successfully implemented on
  the Explorer.&lt;/p&gt;

&lt;p&gt;This proposal does not provide sufficient capability to implement
  forwarding streams such as for &lt;code&gt;make-synonym-stream&lt;/code&gt;,
  &lt;code&gt;make-broadcast-stream&lt;/code&gt;, &lt;code&gt;make-concatenated-stream&lt;/code&gt;, &lt;code&gt;make-two-way-stream&lt;/code&gt;, or
  &lt;code&gt;make-echo-stream&lt;/code&gt;.  The generic function approach does not lend itself as
  well to that as a message passing model where the intermediary does not
  need to know what all the possible messages are.  A possible way of
  extending it for that would be to define a class&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;    (defclass stream-generic-function (standard-generic-function) ())
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to be used as the :generic-function-class option for all of the I/O
  generic functions.  This would then permit doing something like&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (defmethod no-applicable-method ((gfun stream-generic-function) &amp;amp;rest args)
    (if (streamp (first args))
	(apply #&#39;stream-operation-not-handled (first args) gfun (rest args))
      (call-next-method)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where stream-operation-not-handled is a generic function whose default
  method signals an error, but forwarding streams can define methods that
  will create a method to handle the unexpected operation.  (Perhaps
  &lt;code&gt;no-applicable-method&lt;/code&gt; should be changed to take two required arguments
  since all generic functions need at least one required argument, and
  that would make it unnecessary to define a new generic function class
  just to be able to write this one method.)&lt;/p&gt;

&lt;p&gt;Another thing that is not addressed here is a way to cause an instance
  of a user-defined stream class to be created from a call to the &lt;code&gt;open&lt;/code&gt;
  function.  That should be part of a separate issue for generic functions
  on pathnames.  If that capability were available, then &lt;code&gt;pathname&lt;/code&gt; and
  &lt;code&gt;truename&lt;/code&gt; should be required to be generic functions.&lt;/p&gt;

&lt;p&gt;An earlier draft defined just two classes, &lt;code&gt;fundamental-input-stream&lt;/code&gt; and
  &lt;code&gt;fundamental-output-stream&lt;/code&gt;, that were used for both character and binary
  streams.  It isn&amp;rsquo;t clear whether that simple approach is sufficient or
  whether the larger set of classes is really needed.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>These Months in Common Lisp Q4 2018</title>
      <link>/blog/these-months-in-common-lisp-q4-2018/</link>
      <pubDate>Tue, 15 Jan 2019 20:01:30 +0200</pubDate>
      
      <guid>/blog/these-months-in-common-lisp-q4-2018/</guid>
      <description>

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q1-2018/&#34;&gt;Q1 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q2-2018/&#34;&gt;Q2 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q3-2018/&#34;&gt;Q3 2018&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to do this for a year and here we are ! I don&amp;rsquo;t think I&amp;rsquo;ll
carry on, with this format at least.&lt;/p&gt;

&lt;p&gt;If I missed anything crucial: you have comments and PRs: &lt;a href=&#34;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/&#34;&gt;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy (re)discoveries !&lt;/p&gt;

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html&#34;&gt;Debugging – the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/iteration.html&#34;&gt;Loop, iteration, mapping – the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a9at82/clexercise_common_lisp_learning_system_running_on/&#34;&gt;cl-exercise: Common Lisp Learning System running on browsers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;announcements&#34;&gt;Announcements&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;various &lt;a href=&#34;http://www.sbcl.org/all-news.html&#34;&gt;SBCL releases&lt;/a&gt; (from 1.4.13 to 1.4.15) (&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9s6nen/sbcl_1413_released/&#34;&gt;not many changes you think ?&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/aaxp2c/release_corman_lisp_31_sharplisperscormanlisp/&#34;&gt;Release of Corman Lisp 3.1 (Windows)&lt;/a&gt;, with &lt;a href=&#34;https://chaoticlab.io/lisp/update/2018/12/30/corman-3-1-release.html&#34;&gt;personal notes&lt;/a&gt; (also &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/a3hhpa/the_upcoming_release_of_corman_lisp_31_issue_40/&#34;&gt;this thread&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://european-lisp-symposium.org/2019/index.html&#34;&gt;European Lisp Symposium 2019 - Call for Papers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Ragnaroek/dandelion&#34;&gt;Dandelion, Eclipse IDE plugin, updated for SBCL 1.4.10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/12/december-2018-quicklisp-dist-update-now.html&#34;&gt;December Quicklisp update&lt;/a&gt;, &lt;a href=&#34;http://blog.quicklisp.org/2018/10/october-2018-quicklisp-dist-update-now.html&#34;&gt;october&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://open.kattis.com/help&#34;&gt;Common Lisp is now available to use at Kattis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/r/drmeister/cando/&#34;&gt;CANDO - A Computational Chemistry programming environment integrating Common Lisp and C++ based on the Jupyter notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tarballs-are-good/coalton&#34;&gt;Coalton, a dialect of ML embedded in Common Lisp (alpha)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;Ulubis - A Wayland compositor written in Common Lisp&#34;&gt;Ulubis - A Wayland compositor written in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/DataLinkDroid/iso-8601-date&#34;&gt;ISO 8601 date/time library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/terminal625/sucle&#34;&gt;Voxel game engine (Minecraft)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/Theemacsshibe/magrathea&#34;&gt;magrathea: chaotic-neutral web security for Hunchentoot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fjames86/schannel&#34;&gt;schannel: Common Lisp Windows SChannel API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9qguq3/qbase64_a_fast_and_flexible_base64_encoderdecoder/&#34;&gt;qbase64: A fast and flexible base64 encoder/decoder in Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://addons.mozilla.org/en-US/firefox/addon/beautify-practical-common-lisp/&#34;&gt;Beautify Practical Common Lisp, Firefox extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/alex-gutev/static-dispatch/&#34;&gt;static-dispatch: Static generic function dispatch. The purpose is to provide an optimization in cases where the usual dynamic dispatch is too slow, and the dynamic features are not required&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/akamai/cl-http2-protocol&#34;&gt;cl-http2-protocol: HTTP/2 interop library in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;cl-punch: Scala-like and CL21-like anonymous lambda literal&#34;&gt;cl-punch: Scala-like and CL21-like anonymous lambda literal&lt;/a&gt; See other &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#lambda-shorthands&#34;&gt;lambda shorthands&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.ccs.neu.edu/home/dorai/mbe/mbe-lsp.html&#34;&gt;Scheme macros for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/patrikhaslum/INVAL&#34;&gt;The INVAL plan validator, and other PDDL tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/DataLinkDroid/slk-581&#34;&gt;Australian Government statistics collection library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/aaxsas/easybind_easy_local_binding_for_common_lisp/&#34;&gt;Easy local bindings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/stacksmith/cl-fm&#34;&gt;cl-fm - a file manager using cl-cffi-gtk (seems staling. &amp;ldquo;not ready for prime time&amp;rdquo;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/rpav/cl-interval&#34;&gt;cl-intervals: Intervals and interval trees for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GUI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://notabug.org/cage/nodgui&#34;&gt;nodgui - yet another Tcl/Tk-based GUI package for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.ystok.ru/products/ywidgets/&#34;&gt;YstokWidgets Professional Edition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/~loliveira/ediware/midgets/doc/&#34;&gt;MIDGETS - A collection of CAPI widgets and utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/stacksmith/subtext&#34;&gt;subtext: A mostly-text-based UI bridges Common Lisp objects and runs of text. Minimal text-based user interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developer utilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hjudt/s2i-lisp&#34;&gt;s2i-lisp: Common Lisp + Quicklisp OpenShift Build Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fisxoj/lisp-images&#34;&gt;lisp-images: Docker images for common lisp development&lt;/a&gt; (with some others, see the awesome-list)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/HiPhish/quicklisp.nvim&#34;&gt;Quicklisp.nvim - Common Lisp package management within Neovim&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://jscl-project.github.io/&#34;&gt;JSCL 0.7.0 now supports CLOS thanks to the work of vlad-km&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a954yf/next_browser_120_is_out/&#34;&gt;Next browser 1.2.0 is out!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cxxxr/lem/releases&#34;&gt;Lem editor 1.5 released with executables, rust-mode, nim-mode, html-mode, jsx, calc-mode, ncurses for windows, experimental lsp-mode, support for async processes, python and scheme repl and more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(re)discoveries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mmontone/cl-rest-server&#34;&gt;cl-rest-server: Serve REST APIs from Common Lisp, Swagger support &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lmj/lfarm&#34;&gt;lfarm - a library for distributing work across machines (on top of lparallel and usocket)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/willijar/cl-docutils&#34;&gt;cl-docutils: implementation of Docutils. Includes a parser for the reStructured format, writers to html and latex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tarballs-are-good/formulador&#34;&gt;formulador: render math formulas in 2D in your terminal!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mkoeppe/cl-bibtex&#34;&gt;cl-bibtex: A compatible re-implementation of the BibTeX program in Common Lisp, with a BST-to-CL compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://bitbucket.org/budden/clcon/wiki/Screenshots&#34;&gt;clcon - a Common Lisp editor (tcl/tk, mostly russian)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/y2q-actionman/with-c-syntax&#34;&gt;C language syntax embedded in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;articles&#34;&gt;Articles&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9pf2nd/this_old_lisp/&#34;&gt;This Old Lisp (on CCL)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5952920/&#34;&gt;How the strengths of Lisp-family languages facilitate building complex and flexible bioinformatics applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisper.in/nlp-date-parser&#34;&gt;Writing a natural language date and time parser - internals of the Common Lisp library Chronicity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nl.movim.eu/?blog/phoe%40movim.eu/a9391f4b-485e-4f3a-ae02-051a5fc65ed1&#34;&gt;validate-superclass explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nl.movim.eu/?blog/phoe%40movim.eu/cffi-arrays-versus-static-vectors-a-comparison-SCutJQ&#34;&gt;CFFI arrays versus STATIC-VECTORS: a comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nl.movim.eu/?blog/phoe%40movim.eu/82419fb5-a24c-4350-a9c8-c7ae8c6aa2a6&#34;&gt;Dumping Common Lisp streams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nl.movim.eu/?blog/phoe%40movim.eu/killing-common-lisp-methods-and-classes-b23ADB&#34;&gt;Killing Common Lisp methods and classes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://eshamster.hatenablog.com/entry/play-define-method-combination-01&#34;&gt;Funny method combinations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.darkchestnut.com/2018/hunchentoot_custom_sessions/&#34;&gt;Implementing Hunchentoot custom sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/overview-of-documentation-generators/&#34;&gt;Overview of Documentation Generators (codex, coo, declt, staple, cldomain)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/TomLisankie/Learning-Lisp&#34;&gt;Challenging myself to learn Common Lisp in one month&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fourier.github.io/lisp/2019/01/02/reflex-map.html&#34;&gt;Converter of maps from Reflex Arena to QuakeWorld. cl-yacc, 3d-matrices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://two-wrongs.com/debugging-common-lisp-in-slime.html&#34;&gt;Debugging Common Lisp in Slime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www-fourier.ujf-grenoble.fr/~sergerar/Papers/Packaging.pdf&#34;&gt;Packages in Common Lisp, a tutorial (pdf)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.darkchestnut.com/2018/how-to-write-5am-test-fixtures/&#34;&gt;How to write test fixtures for FiveAM - Dark Chestnut&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://allegrograph.com/franz-and-semantic-web-company-partner-to-create-a-noam-chomsky-knowledge-graph/&#34;&gt;Franz and Semantic Web Co. Partner to Create a Noam Chomsky Knowledge Graph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://michaelgogins.tumblr.com/post/178126207468/composing-in-lisp&#34;&gt;Composing in Lisp with Csound&lt;/a&gt; (see also &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#audio&#34;&gt;audio and music composition software&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://terranostra.one/posts/Blogging-with-Lisp.html&#34;&gt;Blogging with Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://notes.eatonphil.com/compiler-basics-lisp-to-assembly.html&#34;&gt;Compiler basics: lisp to assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.webofstories.com/play/marvin.minsky/44&#34;&gt;Marvin Minsky - Scientist - The beauty of the Lisp language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GUIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/mcclim/posts/Yule-progress-report.html&#34;&gt;McCLIM Yule progress report - towards 1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a31oxr/demo_sbcl_script_using_gtk/&#34;&gt;Demo SBCL script using Gtk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On games:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://techsnuffle.com/2018/12/07/reasons-why-lisp-games-suffer-corrections&#34;&gt;Baggers responds to &amp;lsquo;Reasons why Lisp games suffer&amp;rsquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://reader.tymoon.eu/article/370&#34;&gt;About Making Games in Lisp - Gamedev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;Creating a (Non-Trivial) Lisp Game in 2018&#34;&gt;Creating a (Non-Trivial) Lisp Game in 2018&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;discussion&#34;&gt;Discussion&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a7156w/lisp_and_the_remote_agent/&#34;&gt;Lisp and the remote agent - with an AMA of Ron Garret&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a5ggd4/how_to_make_common_lisp_popular/&#34;&gt;How to make (Common) Lisp popular?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9r9xy6/feedback_from_a_new_lispworks_user/&#34;&gt;Feedback from a new LispWorks user&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9qh3op/how_is_lispworks_the_company_doing/&#34;&gt;how is LispWorks the company going ?&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/a3r4hb/how_do_you_normally_use_a_program_once_written/&#34;&gt;How do you normally use a program once written ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9q6bum/how_does_common_lisp_implement_hot_code_reloading/&#34;&gt;How does Common Lisp implement hot code reloading?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a10629/structs_vs_parametric_polymorphism_an_answer_to/&#34;&gt;Structs vs Parametric Polymorphism (an answer to the &amp;ldquo;switching from Common Lisp to Julia - thoughts ?&amp;rdquo; post)&lt;/a&gt; also &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9y425b/switching_from_common_lisp_to_julia_your_thoughts/&#34;&gt;this discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/9os171/how_to_work_on_a_project_and_make_sure/&#34;&gt;How to work on a project and make sure dependencies are tracked correctly?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/a2hkq0/does_anyone_else_hate_loop_cl/&#34;&gt;Does anyone else hate LOOP?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9xd4gy/what_does_it_take_to_understand_the_true_power_of/&#34;&gt;What does it take to understand the true power of Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9qfrxe/how_lisp_made_your_life_easier/&#34;&gt;How did Lisp make your life easier ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9zpts4/should_local_variables_be_avoided_when_possible/&#34;&gt;Should local variables be avoided when possible when doing functional programming?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9upt86/abcl/&#34;&gt;Is ABCL an active project and does it support JRE 1.11?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9q68y8/has_the_gnu_coreutils_ever_been_implemented_in/&#34;&gt;Has the Gnu Coreutils ever been implemented in Lisp? If not, would that be a worthwhile project?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sirherrbatka.github.io/blog/2018/10/14/classes-are-not-interactions/&#34;&gt;&amp;ldquo;Classes are not interactions!&amp;rdquo; by shka&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;screencasts&#34;&gt;Screencasts&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=mbdXeRBbgDM&amp;amp;app=desktop&#34;&gt;2018 LLVM Developers’ Meeting: C. Schafmeister “Lessons Learned Implementing Common Lisp with LLVM”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCMV8p6Lb-bd6UZtTc_QD4zA&#34;&gt;A pile of parens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/pZO6HSKHWLg&#34;&gt;Pushing Pixels with Lisp - 61 - Stenciling (Failed attempt)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;common-lisp-vs&#34;&gt;Common Lisp VS &amp;hellip;&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/ac9mm9/how_common_lisp_community_survived_without_the/&#34;&gt;How did the Common Lisp community survived without the equivalent of clojure.spec ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Why Deftask Chose Common Lisp</title>
      <link>/blog/why-deftask-chose-common-lisp/</link>
      <pubDate>Fri, 11 Jan 2019 12:21:30 +0100</pubDate>
      
      <guid>/blog/why-deftask-chose-common-lisp/</guid>
      <description>&lt;p&gt;We heard about &lt;a href=&#34;https://github.com/deftask/&#34;&gt;Deftask&lt;/a&gt;, a task
management app for teams, a few days ago, in an article about the
&lt;a href=&#34;https://lisper.in/nlp-date-parser&#34;&gt;internals of the Chronicity library&lt;/a&gt;. Deftask
uses Common Lisp for its backend and its command-line app. This
reasonates with the fact that &lt;a href=&#34;/blog/why-turtl-switched-from-lisp-to-js&#34;&gt;Turtl doesn&amp;rsquo;t use CL anymore&lt;/a&gt;. So I
asked Deftask&amp;rsquo;s author: why did you go with CL ?&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;More than anything else, I think its down to fun and productivity. I
feel that I am at my most productive when I writing CL in Emacs+SLIME.
It is probably down to the edit-compile-debug cycle which is much
shorter in CL compared to other languages. I originally worked on CL
way back in 2006-08 when I was with Cleartrip. Since then, I have
worked on a number of platforms (frontend js, node, iOS, C, Java,
etc.) but always wanted to go back to writing CL full time.&lt;/p&gt;

&lt;p&gt;So when I left my last job a little over a year back, I had already
made up my mind that the next thing I build would be in CL.&lt;/p&gt;

&lt;p&gt;The lack of libraries (or rather, well supported libraries) is a
problem, but honestly after over eight years of not working on Lisp,
it doesn&amp;rsquo;t bother me much.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you already build software/services in CL, apart
the libraries we can see on your github profile ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I mentioned I worked at Cleartrip for a little over two years. I
was part of the team that managed the flight search engine,
Unfortunately most of what we did there is gone forever. A small
sliver of our work there resulted in &lt;a href=&#34;https://lisper.in/restarts&#34;&gt;https://lisper.in/restarts&lt;/a&gt;
(backstory: &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7k85sf/a_tutorial_on_conditions_and_restarts/&#34;&gt;https://www.reddit.com/r/lisp/comments/7k85sf/a_tutorial_on_conditions_and_restarts/&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you have enough libraries to build your service ? How&amp;rsquo;s deployment and
maintenance going ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well you could say I had enough libraries. Although I still ended up
writing a mini web framework on top of Hunchentoot. Another thing I
wrote is my own Lisp-to-SQL converter. Hope to open source both of
these one day. Apart from that I use drakma, postmodern, djula, plump,
lparallel, cl-json to name a few (alongwith the usual suspects like
alexandria and local-time).&lt;/p&gt;

&lt;p&gt;Deployment and maintenance is extremely simple - I just update the
relevant git branch and restart the service. At some point when the
restarts become costly I might add the ability to reload changed code
in the running service.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Thanks to him !&lt;/p&gt;

&lt;p&gt;Below the backstory from reddit:&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Hey that was written by me! (Aside: I redirected the page to point to the latest version of this post on my new blog)&lt;/p&gt;

&lt;p&gt;Fun fact: I wrote this post way back in 2008 while working for an online travel portal. This was based on some actual work we&amp;rsquo;d done there. At that time, flight travel in India had started to boom. This I think went hand in hand with a bunch of online travel companies (including ours) gaining a lot of momentum.&lt;/p&gt;

&lt;p&gt;To be more competitive, a couple of airlines decided that they wanted to introduce new discounted fares much more frequently than they were doing earlier. The only problem was that they were unable to upload their wonky fare rules in the GDS properly, so they started distributing excel sheets to travel agents with manual instructions on how to apply them.&lt;/p&gt;

&lt;p&gt;So our business team starts sending these sheets over to us, and initially, the frequency was low so we just manually hard coded these rules. However then they started sending these sheets every week or so which made our life hell. So we asked asked our business team to &amp;ldquo;translate&amp;rdquo; the airline&amp;rsquo;s excel sheets and instructions into a csv, which was subsequently interpreted by a simple rules engine that we wrote.&lt;/p&gt;

&lt;p&gt;The only problem? Well, as anyone who&amp;rsquo;s dealt with manually created CSVs will tell you, there were a lot of errors. This didn&amp;rsquo;t really help matters much. We then added a couple of restarts to our CSV parser which allowed us to correct these issues interactively. This made life much better for us &amp;ndash; it was a lot easier than, say, getting a list of errors in a terminal and switching back and forth between the terminal window and the editor to correct them.&lt;/p&gt;

&lt;p&gt;Later on we plonked the CSV parser behind hunchentoot and asked our bizdev guy to upload the file there. A handle-bind around the parser collected all the errors in one go and showed them in a nicely formatted way in the browser (see the last section of the post). And so it was no longer our problem :-)&lt;/p&gt;

&lt;p&gt;Eventually these airlines decided they wanted to update fare rules daily. Thankfully our &amp;ldquo;business rules engine&amp;rdquo; was upto the task. Due to automatic feedback, our friend in bizdev became an expert at uploading the fare rules as soon as they came in. And for quite some time, we were the only ones who could show these cheap fares within minutes of them coming in (if I remember correctly, other portals would take hours to upload the same rules).&lt;/p&gt;

&lt;p&gt;Ours was a small team, and we had to manage this in addition to a lot of other things. If it weren&amp;rsquo;t for CL&amp;rsquo;s condition system, I doubt we could have solved this as smoothly as we did. In particular, interactive restarts allowed us (devs) to correct CSV errors without wasting a lot of our own time, and without needing to build a full-fledged UI for a non-dev. And when the time did come for a UI, it was dead easy to write a web fontend on top of it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Q: Did you ever work or need an optimal solution to the Tavelling Salesman Problem?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nope. Domestic flight travel in India is simple&amp;hellip; point to point or max over two legs. For international flights we used QPX.&lt;/p&gt;

&lt;p&gt;(QPX was ITA software&amp;rsquo;s flight search engine. Probably among the biggest software systems written in Lisp. It now powers Google Flights (I think).)&lt;/p&gt;

&lt;hr /&gt;
</description>
    </item>
    
    <item>
      <title>Why Turtl Switched From CL to Js</title>
      <link>/blog/why-turtl-switched-from-lisp-to-js/</link>
      <pubDate>Fri, 11 Jan 2019 10:21:18 +0100</pubDate>
      
      <guid>/blog/why-turtl-switched-from-lisp-to-js/</guid>
      <description>&lt;p&gt;Turtl is a very well done, secure collaborative notebook web app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://turtlapp.com&#34;&gt;https://turtlapp.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its api backend is built in Common Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/turtl/api/&#34;&gt;https://github.com/turtl/api/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is based on many async libraries the developer wrote for Turtl,
like the &lt;a href=&#34;https://github.com/orthecreedence/wookie&#34;&gt;Wookie&lt;/a&gt; async HTTP
server.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;is&amp;rdquo; ? No, was :/ Even though this repository is still maintained
(latest commit: 2nd of december 2018), it is deprecated and the
&lt;a href=&#34;https://github.com/turtl/server&#34;&gt;new server&lt;/a&gt; is written in NodeJS. I
asked Andrew for the reasons behind this, here&amp;rsquo;s his answer.&lt;/p&gt;

&lt;p&gt;(in a hurry to spread FUD ? Don&amp;rsquo;t miss this posts&amp;rsquo;s twin,
&lt;a href=&#34;/blog/why-deftask-chose-common-lisp&#34;&gt;Why Deftask chose Common Lisp&lt;/a&gt;
;) See also some
&lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies&#34;&gt;companies using Common Lisp&lt;/a&gt;)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;It was not an easy decision to replace CL with javascript. I find CL
to be elegant, fast, stable, and above all else, easy to debug (having
the ability to rewrite the program as it&amp;rsquo;s running is insanely
useful). In fact, I still miss lisp and ask myself all the time if I
made the right choice.&lt;/p&gt;

&lt;p&gt;I think I did, though.&lt;/p&gt;

&lt;p&gt;The path I went with CL was a hard one. I wanted to be able to use
asynchronous programming because for the type of work I do (a lot of
making APIs that talk to other services with very little CPU work)
it&amp;rsquo;s hard to get much more performant. So I embarked on creating
cl-async/cl-libuv (originally cl-libevent) and wookie, along with a
few other drivers. Everything I built worked great (and still works
great, as far as I can tell) however when things did go wrong, there
was nobody to run ideas by and nobody to really help me&amp;hellip;I had built
all these things myself, and I also had to be responsible for fixing
them when they broke. On top of having to maintain everything (and it
did break from time to time) there is not much in the way of packages
to help me out. For instance, there&amp;rsquo;s a package to upload files to S3,
but it&amp;rsquo;s not async at all&amp;hellip;I had to build this from scratch. There
are more cases of this as well.&lt;/p&gt;

&lt;p&gt;With CL, it felt like I was constantly fighting the tide. I was
constantly battling just to get basic things working that are already
solved problems in other languages (Node).&lt;/p&gt;

&lt;p&gt;There was help and support from the community along the way, but I was
mostly fighting it alone. I think the straw that broke the camel&amp;rsquo;s
back was when a few people started making copycat projects that added
no real value (other than benchmarking fast) but stole mindshare from
all the work I had put in. It was the &amp;ldquo;well, that project is not
exactly what I want so I&amp;rsquo;ll make my own from scratch&amp;rdquo; mindset that
everyone always warned about when I was starting with CL (but I
ignored). I had really hoped the community would have helped propel
the async ecosystem I was building forward, but I just don&amp;rsquo;t think
there&amp;rsquo;s enough people using CL for that to happen.&lt;/p&gt;

&lt;p&gt;So between having to maintain everything myself and people putting out
worthless copycat projects that ended up going nowhere, I didn&amp;rsquo;t have
the energy anymore.&lt;/p&gt;

&lt;p&gt;Honestly, it took me about a week of work, just nights and weekends,
to reprogram the server in javascript. Granted, most of the &amp;ldquo;how
should this work?&amp;rdquo; architecture stuff was already done so it was more
of a rewrite than a build-from-scratch situation, but Node is fast to
build APIs in. I&amp;rsquo;m decently fluent in javascript and the amount
packages available is so immense that it just made sense.&lt;/p&gt;

&lt;p&gt;On top of being fast to build in, it&amp;rsquo;s a well-traveled road. I don&amp;rsquo;t
have people emailing me six times a day asking how to install the
server like I did with CL. I don&amp;rsquo;t have to make weird custom loaders
to run the app on any hosting providers&amp;hellip;everyone supports Node. I
don&amp;rsquo;t have to deal with weird FFI errors or libuv nuances. I don&amp;rsquo;t
have to deal with quicklisp&amp;rsquo;s &amp;ldquo;all or nothing&amp;rdquo; packaging that doesn&amp;rsquo;t
support version pinning. I don&amp;rsquo;t have to restart the server every 20
days because of some memory leak I have yet to track down somewhere
between cl-libuv, cl-async, wookie, and turtl. There&amp;rsquo;s a whole set of
bullshit I just don&amp;rsquo;t have to deal with anymore.&lt;/p&gt;

&lt;p&gt;So I do miss lisp. I&amp;rsquo;d eventually like to build more things in it
(like games). But I don&amp;rsquo;t think I&amp;rsquo;ll ever touch web stuff in CL again,
and the whole journey left a bitter taste in my mouth. Sure I could
have dropped the async thing and just done a threaded server in
hunchentoot and cl-postgres. But once I decided I was going to
reprogram everything anyway, it just made sense to go with Node.&lt;/p&gt;

&lt;p&gt;I took on more work than I could realistically manage, and hoped that
the community would help&amp;hellip;but the CL community is small enough that
it was a losing bet and I got burned out.&lt;/p&gt;

&lt;p&gt;Hopefully none of this discourages you. CL is a great language. The
community is a mix though. Some of the people in the community are
smart and dedicated, and work on cool projects at a pace they can
maintain. You won&amp;rsquo;t see articles about these projects, and many will
only have a handful of stars on Github (don&amp;rsquo;t measure CL projects by
stars). Seek these projects and these people out, and build things
with them. There is a quiet corner of the internet, with a handful of
people building amazing things in lisp.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Before commenting on this, I think we must realize what he achieved,
and that he went the hard way.&lt;/p&gt;

&lt;p&gt;Now don&amp;rsquo;t miss &lt;a href=&#34;/blog/why-deftask-chose-common-lisp&#34;&gt;Why Deftask chose Common Lisp&lt;/a&gt; !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Introducing Replic: an executable and a library to build a readline app in no time</title>
      <link>/blog/introducing-replic-a-readline-app-in-no-time/</link>
      <pubDate>Wed, 09 Jan 2019 14:41:57 +0100</pubDate>
      
      <guid>/blog/introducing-replic-a-readline-app-in-no-time/</guid>
      <description>&lt;p&gt;When I started dabbling in CL, I tried to build a readline application
to see how it goes. I found
&lt;a href=&#34;https://github.com/vindarel/cl-readline&#34;&gt;cl-readline&lt;/a&gt; (I&amp;rsquo;m only the
new maintainer) and it went smoothly. So I built a second and a third
app, and found many things to refactor and provide out of the box: now
comes &lt;a href=&#34;https://github.com/vindarel/replic/&#34;&gt;replic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It comes as a library (now in Quicklisp, since 2018-01) and as an
executable. The library does the following for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it builds the repl loop, catches a C-c, a C-d, errors,&lt;/li&gt;
&lt;li&gt;it asks confirmation to quit,&lt;/li&gt;
&lt;li&gt;it asks depending on a .conf and a lispy config file,&lt;/li&gt;
&lt;li&gt;it reads parameters from a config file,&lt;/li&gt;
&lt;li&gt;it prints the help of all or one command (with optional highlighting),&lt;/li&gt;
&lt;li&gt;and more importantly it handles the completion of commands and of their arguments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, instead of this &amp;ldquo;repl&amp;rdquo; loop:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (handler-case
      (do ((i 0 (1+ i))
           (text &amp;quot;&amp;quot;)
           (verb &amp;quot;&amp;quot;)
           (function nil)
           (variable nil)
           (args &amp;quot;&amp;quot;))
          ((string= &amp;quot;quit&amp;quot; (str:trim text)))

        (handler-case
            (setf text
                  (rl:readline :prompt (prompt)
                               :add-history t))
          (#+sbcl sb-sys:interactive-interrupt ()
                  (progn
                    (when (confirm)
                      (uiop:quit)))))

        (if (string= text &amp;quot;NIL&amp;quot;)
            ;; that&#39;s a C-d, a blank input is just &amp;quot;&amp;quot;.
            (when (confirm)
              (uiop:quit)))

        (unless (str:blank? text)
          (setf verb (first (str:words text)))
          (setf function (if (replic.completion:is-function verb)
                             ;; might do better than this or.
                             (replic.completion:get-function verb)))
          (setf variable (if (replic.completion:is-variable verb)
                             (replic.completion:get-variable verb)))
          (setf args (rest (str:words text)))


          (if (and verb function)
              (handler-case
                  ;; Call the function.
                  (apply function args)
                (#+sbcl sb-sys:interactive-interrupt (c)
                        (declare (ignore c))
                        (terpri))
                (error (c) (format t &amp;quot;Error: ~a~&amp;amp;&amp;quot; c)))

              (if variable
                  (format t &amp;quot;~a~&amp;amp;&amp;quot; (symbol-value variable))
                  (format t &amp;quot;No command or variable bound to ~a~&amp;amp;&amp;quot; verb)))

          (finish-output)

          (when (and *history*
                     *write-history*)
            (rl:write-history &amp;quot;/tmp/readline_history&amp;quot;))
          ))

    (error (c)
      (format t &amp;quot;~&amp;amp;Unknown error: ~&amp;amp;~a~&amp;amp;&amp;quot; c)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;you call:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(replic:repl)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To turn all exported functions of a package into commands, use&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(replic:functions-to-commands :my-package)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and you can find them into the readline app.&lt;/p&gt;

&lt;p&gt;Setting the completion of commands is easy, we use
&lt;code&gt;(replic.completion:add-completion &amp;quot;my-function&amp;quot; &amp;lt;list-or-lambda&amp;gt;&lt;/code&gt;. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(in-package :replic.user)

(defparameter *names* &#39;()
  &amp;quot;List of names (string) given to `hello`. Will be autocompleted by `goodbye`.&amp;quot;)

(defun hello (name)
  &amp;quot;Takes only one argument. Adds the given name to the global
  `*names*` variable, used to complete arguments of `goodbye`.
  &amp;quot;
  (format t &amp;quot;hello ~a~&amp;amp;&amp;quot; name)
  (push name *names*))

(defun goodbye (name)
  &amp;quot;Says goodbye to name, where `name` should be completed from what was given to `hello`.&amp;quot;
  (format t &amp;quot;goodbye ~a~&amp;amp;&amp;quot; name))

(replic.completion:add-completion &amp;quot;goodbye&amp;quot; (lambda () *names*))

(export &#39;(hello goodbye))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example can be used with the &lt;em&gt;executable&lt;/em&gt;. What it does is read
your code from a lisp file (&lt;code&gt;~/.replic.lisp&lt;/code&gt; or an argument on the
command line) and it turns the exported functions into commands, for
which we can specify custom completion.&lt;/p&gt;

&lt;p&gt;For more details, see the readme.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I use this currently in three apps of mine (like
&lt;a href=&#34;https://github.com/vindarel/cl-torrents&#34;&gt;cl-torrents&lt;/a&gt;). It&amp;rsquo;s
simple. It could be more: it could infer the arguments&amp;rsquo; type, do fuzzy
completion, maybe integrate a Lisp editor (Lem) or a lispy shell
(shcl), separate the commands in apps, expose hooks, have a set of
built-in shell related utilities, highlight the input line, it could
be web-based,…&lt;/p&gt;

&lt;p&gt;For now it&amp;rsquo;s going smoothly.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll finish by recalling that it&amp;rsquo;s amazing to be able to ship
self-contained executables to users !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Debugging in Common Lisp</title>
      <link>/blog/debugging-in-common-lisp/</link>
      <pubDate>Thu, 20 Dec 2018 12:26:02 +0100</pubDate>
      
      <guid>/blog/debugging-in-common-lisp/</guid>
      <description>

&lt;p&gt;You entered this new world of Lisp and now wonder: how can we debug
what&amp;rsquo;s going on ?  How is it more interactive than in other platforms
?  What does bring the interactive debugger appart from stacktraces ?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;note&lt;/em&gt;: this tutorial is available on the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/debugging.html&#34;&gt;Common Lisp Cookbook&lt;/a&gt; and it will receive updates there.&lt;/p&gt;

&lt;p&gt;If you want step-by-step examples of interactive debugging with nice
screenshots and gifs, see the blog posts in the References section
below.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#print-debugging&#34;&gt;Print debugging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#logging&#34;&gt;Logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-the-powerful-repl&#34;&gt;Using the powerful REPL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#inspect-and-describe&#34;&gt;Inspect and describe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-interactive-debugger&#34;&gt;The interactive debugger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#trace&#34;&gt;Trace&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#tracing-method-invocation&#34;&gt;Tracing method invocation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#step&#34;&gt;Step&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#break&#34;&gt;Break&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#breakpoints-in-slime&#34;&gt;Breakpoints in Slime&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#advise-and-watch&#34;&gt;Advise and watch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#unit-tests&#34;&gt;Unit tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#references&#34;&gt;References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;print-debugging&#34;&gt;Print debugging&lt;/h2&gt;

&lt;p&gt;Well of course we can use the famous technique of &amp;ldquo;print
debugging&amp;rdquo;. Let&amp;rsquo;s just recap a few print functions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;print&lt;/code&gt; works, it prints a READable representation of its argument,
which means what is &lt;code&gt;print&lt;/code&gt;ed can be &lt;code&gt;read&lt;/code&gt; back in by the Lisp
reader.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;princ&lt;/code&gt; focuses on an &lt;em&gt;aesthetic&lt;/em&gt; representation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;format t &amp;quot;~a&amp;quot; …)&lt;/code&gt;, with the &lt;em&gt;aesthetic&lt;/em&gt; directive, prints a string (in &lt;code&gt;t&lt;/code&gt;, the standard output
stream) and returns nil, whereas &lt;code&gt;format nil …&lt;/code&gt; doesn&amp;rsquo;t print anything
and returns a string. With many format controls we can print several
variables at once.&lt;/p&gt;

&lt;h2 id=&#34;logging&#34;&gt;Logging&lt;/h2&gt;

&lt;p&gt;Logging is a good evolution from print debugging ;)&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/sharplispers/log4cl/&#34;&gt;log4cl&lt;/a&gt; is the popular,
de-facto logging library but it isn&amp;rsquo;t the only one. Download it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload :log4cl)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and let&amp;rsquo;s have a dummy variable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defvar *foo* &#39;(:a :b :c))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can use log4cl with its &lt;code&gt;log&lt;/code&gt; nickname, then it is as simple to use as:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(log:info *foo*)
;; &amp;lt;INFO&amp;gt; [13:36:49] cl-user () - *FOO*: (:A :B :C)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can interleave strings and expressions, with or without &lt;code&gt;format&lt;/code&gt;
control strings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(log:info &amp;quot;foo is &amp;quot; *foo*)
;; &amp;lt;INFO&amp;gt; [13:37:22] cl-user () - foo is *FOO*: (:A :B :C)
(log:info &amp;quot;foo is ~{~a~}&amp;quot; *foo*)
;; &amp;lt;INFO&amp;gt; [13:39:05] cl-user () - foo is ABC
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With its companion library &lt;code&gt;log4slime&lt;/code&gt;, we can interactively change
the log level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;globally,&lt;/li&gt;
&lt;li&gt;per package,&lt;/li&gt;
&lt;li&gt;per function,&lt;/li&gt;
&lt;li&gt;and by CLOS methods and CLOS hierarchy (before and after methods).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is very handy, when we have a lot of output, to turn off the
logging of functions or packages we know to work, and thus narrowing
our search to the right area. We can even save this configuration and
re-use it in another image, be it on another machine.&lt;/p&gt;

&lt;p&gt;We can do all this through commands, keyboard shortcuts and also through a
menu or mouse clicks.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://github.com/sharplispers/log4cl/raw/master/images/screenshot-15.png&#34; alt=&#34;&amp;quot;changing the log level with log4slime&amp;quot;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;We invite you to read log4cl&amp;rsquo;s readme.&lt;/p&gt;

&lt;h2 id=&#34;using-the-powerful-repl&#34;&gt;Using the powerful REPL&lt;/h2&gt;

&lt;p&gt;Part of the joy of Lisp is the excellent REPL. Its existence usually
delays the need to use other debugging tools, if it doesn&amp;rsquo;t annihilate
them for the usual routine.&lt;/p&gt;

&lt;p&gt;As soon as we define a function, we can try it in the REPL. In Slime,
compile a function with &lt;code&gt;C-c C-c&lt;/code&gt; (the whole buffer with &lt;code&gt;C-c C-k&lt;/code&gt;),
switch to the REPL with &lt;code&gt;C-c C-z&lt;/code&gt; and try it. Eventually enter the
package you are working on with &lt;code&gt;(in-package :your-package)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The feedback is immediate. There is no need to recompile everything,
nor to restart any process, nor to create a main function and define
command line arguments for use in the shell (we can do this later on
when needed).&lt;/p&gt;

&lt;p&gt;We usually need to create some data to test our function(s). This is a
subsequent art of the REPL existence and it may be a new discipline
for newcomers. A trick is to write the test data alongside your
functions but inside a &lt;code&gt;#+nil&lt;/code&gt; declaration so that only you can
manually compile them:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;    #+nil
    (progn
       (defvar *test-data* nil)
       (setf *test-data* (make-instance &#39;foo …)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you load this file, &lt;code&gt;*test-data*&lt;/code&gt; won&amp;rsquo;t exist, but you can
manually create it with a &lt;code&gt;C-c C-c&lt;/code&gt; away.&lt;/p&gt;

&lt;p&gt;We can define tests functions like this.&lt;/p&gt;

&lt;p&gt;Some do similarly inside &lt;code&gt;#| … |#&lt;/code&gt; comments.&lt;/p&gt;

&lt;p&gt;All that being said, keep in mind to write unit tests when time comes ;)&lt;/p&gt;

&lt;h2 id=&#34;inspect-and-describe&#34;&gt;Inspect and describe&lt;/h2&gt;

&lt;p&gt;These two commands share the same goal, printing a description of an
object, &lt;code&gt;inspect&lt;/code&gt; being the interactive one.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(inspect *foo*)

The object is a proper list of length 3.
0. 0: :A
1. 1: :B

2. 2: :C
&amp;gt; q
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also, in editors that support it, right-click on any object in
the REPL and &lt;code&gt;inspect&lt;/code&gt; them. We are presented a screen where we can
dive deep inside the data structure and even change it.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s have a quick look with a more interesting structure, an object:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass foo ()
    ((a :accessor foo-a :initform &#39;(:a :b :c))
     (b :accessor foo-b :initform :b)))
;; #&amp;lt;STANDARD-CLASS FOO&amp;gt;
(make-instance &#39;foo)
;; #&amp;lt;FOO {100F2B6183}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We right-click on the &lt;code&gt;#&amp;lt;FOO&lt;/code&gt; object and choose &amp;ldquo;inspect&amp;rdquo;. We are
presented an interactive pane (in Slime):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;FOO {100F2B6183}&amp;gt;
--------------------
Class: #&amp;lt;STANDARD-CLASS FOO&amp;gt;
--------------------
 Group slots by inheritance [ ]
 Sort slots alphabetically  [X]

All Slots:
[ ]  A = (:A :B :C)
[ ]  B = :B

[set value]  [make unbound]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we click or press enter on the line of slot A, we inspect it further:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;CONS {100F5E2A07}&amp;gt;
--------------------
A proper list:
0: :A
1: :B
2: :C
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;the-interactive-debugger&#34;&gt;The interactive debugger&lt;/h2&gt;

&lt;p&gt;Whenever an exceptional situation happens (see
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/error_handling.html&#34;&gt;error handling&lt;/a&gt;), the interactive debugger pops
up.&lt;/p&gt;

&lt;p&gt;It presents the error message, available actions (&lt;em&gt;restarts&lt;/em&gt;),
and the backtrace. A few remarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the restarts are programmable, we can create our owns,&lt;/li&gt;
&lt;li&gt;in Slime, press &lt;code&gt;v&lt;/code&gt; on a stacktrace to be redirected to the source
file at the right line,&lt;/li&gt;
&lt;li&gt;hit enter on a frame for more details,&lt;/li&gt;
&lt;li&gt;we can explore the functionnality with the menu that should appear
in our editor. See below in &amp;ldquo;break&amp;rdquo; section for a few
more commands (eval in frame, etc).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usually your compiler will optimize things out and this will reduce
the amount of information available to the debugger. For example
sometimes we can&amp;rsquo;t see intermediate variables of computations. You might
want to print a function argument (with &lt;code&gt;e&lt;/code&gt; to &amp;ldquo;eval in frame&amp;rdquo;, see
below), but you keep getting a &lt;code&gt;Variable XYZ is unbound&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;To fix this, we have to change the optimization choices with &lt;code&gt;declaim&lt;/code&gt;, at the beginning of the file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(declaim (optimize (speed 0) (space 0) (debug 3)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or with &lt;code&gt;declare&lt;/code&gt;, inside a &lt;code&gt;defun&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun my-fun (xyz)
  (declare (optimize (debug 3)))
  …)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and recompile the code,&lt;/p&gt;

&lt;p&gt;or in Emacs and Slime there&amp;rsquo;s a shortcut for this, just use &lt;code&gt;C-u C-c
C-c&lt;/code&gt; (universal argument, &amp;ldquo;slime compile defun&amp;rdquo; with max debug settings).&lt;/p&gt;

&lt;p&gt;Now you should be able to see local variables such as&lt;code&gt;xyz&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;trace&#34;&gt;Trace&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;http://www.xach.com/clhs?q=trace&#34;&gt;trace&lt;/a&gt; allows us to see when a
function was called, what arguments it received, and the value it
returned.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun factorial (n)
  (if (plusp n)
    (* n (factorial (1- n)))
    1))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace factorial)

(factorial 2)
  0: (FACTORIAL 3)
    1: (FACTORIAL 2)
      2: (FACTORIAL 1)
        3: (FACTORIAL 0)
        3: FACTORIAL returned 1
      2: FACTORIAL returned 1
    1: FACTORIAL returned 2
  0: FACTORIAL returned 6
6

(untrace factorial)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To untrace all functions, just evaluate &lt;code&gt;(untrace)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In Slime we also have the shortcut &lt;code&gt;C-c M-t&lt;/code&gt; to trace or untrace a
function.&lt;/p&gt;

&lt;p&gt;If you don&amp;rsquo;t see recursive calls, that may be because of the
compiler&amp;rsquo;s optimizations. Try this before defining the function to be
traced:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(declaim (optimize (debug 3)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output is printed to &lt;code&gt;*trace-output*&lt;/code&gt; (see the CLHS).&lt;/p&gt;

&lt;p&gt;In Slime, we also have an interactive trace dialog with &lt;code&gt;M-x
slime-trace-dialog&lt;/code&gt; bound to &lt;code&gt;C-c T&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;tracing-method-invocation&#34;&gt;Tracing method invocation&lt;/h3&gt;

&lt;p&gt;In SBCL, we can use &lt;code&gt;(trace foo :methods t)&lt;/code&gt; to trace the execution order of method combination (before, after, around methods). For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace foo :methods t)

(foo 2.0d0)
  0: (FOO 2.0d0)
    1: ((SB-PCL::COMBINED-METHOD FOO) 2.0d0)
      2: ((METHOD FOO (FLOAT)) 2.0d0)
        3: ((METHOD FOO (T)) 2.0d0)
        3: (METHOD FOO (T)) returned 3
      2: (METHOD FOO (FLOAT)) returned 9
      2: ((METHOD FOO :AFTER (DOUBLE-FLOAT)) 2.0d0)
      2: (METHOD FOO :AFTER (DOUBLE-FLOAT)) returned DOUBLE
    1: (SB-PCL::COMBINED-METHOD FOO) returned 9
  0: FOO returned 9
9
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;CLOS&lt;/a&gt; section for a tad more information.&lt;/p&gt;

&lt;h2 id=&#34;step&#34;&gt;Step&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;http://www.xach.com/clhs?q=step&#34;&gt;step&lt;/a&gt; is an interactive command with
similar scope than &lt;code&gt;trace&lt;/code&gt;. This:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(step (factorial 2))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;gives an interactive pane with the available restarts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Evaluating call:
  (FACTORIAL 2)
With arguments:
  2
   [Condition of type SB-EXT:STEP-FORM-CONDITION]

Restarts:
 0: [STEP-CONTINUE] Resume normal execution
 1: [STEP-OUT] Resume stepping after returning from this function
 2: [STEP-NEXT] Step over call
 3: [STEP-INTO] Step into call
 4: [RETRY] Retry SLIME REPL evaluation request.
 5: [*ABORT] Return to SLIME&#39;s top level.
 --more--

Backtrace:
  0: ((LAMBDA ()))
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LET ((SB-IMPL::*STEP-OUT* :MAYBE)) (UNWIND-PROTECT (SB-IMPL::WITH-STEPPING-ENABLED #))) #S(SB-KERNEL:LEXENV :FUNS NIL :VARS NIL :BLOCKS NIL :TAGS NIL :TYPE-RESTRICTIONS ..
  2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (STEP (FACTORIAL 2)) #&amp;lt;NULL-LEXENV&amp;gt;)
  3: (EVAL (STEP (FACTORIAL 2)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Stepping is useful, however it may be a sign that you need to simplify your function.&lt;/p&gt;

&lt;h2 id=&#34;break&#34;&gt;Break&lt;/h2&gt;

&lt;p&gt;A call to &lt;a href=&#34;http://www.xach.com/clhs?q=break&#34;&gt;break&lt;/a&gt; makes the program
enter the debugger, from which we can inspect the call stack.&lt;/p&gt;

&lt;h3 id=&#34;breakpoints-in-slime&#34;&gt;Breakpoints in Slime&lt;/h3&gt;

&lt;p&gt;Look at the &lt;code&gt;SLDB&lt;/code&gt; menu, it shows navigation keys and available
actions. Of which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;e&lt;/code&gt; (&lt;em&gt;sldb-eval-in-frame&lt;/em&gt;) prompts for an expression and evaluates
it in the selected frame. This is how we can explore our
intermediate variables.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt; is similar with the addition of pretty printing the result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we are in a frame and detect a suspicious behavior, we can even
re-compile a function at runtime and resume the program execution from
where it stopped (using the &amp;ldquo;step-continue&amp;rdquo; restart).&lt;/p&gt;

&lt;h2 id=&#34;advise-and-watch&#34;&gt;Advise and watch&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;http://www.xach.com/clhs?q=break&#34;&gt;advise&lt;/a&gt; and
&lt;a href=&#34;http://www.xach.com/clhs?q=watch&#34;&gt;watch&lt;/a&gt; are available in some vendor
implementations, like LispWorks. They are not available in
SBCL. &lt;code&gt;advise&lt;/code&gt; allows to modify a function without changing its
source, or to do something before or after its execution, like CLOS&amp;rsquo;
method combination (befor, after around methods).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;watch&lt;/code&gt; allows to specify variables to be displayed in some GUI during
the program execution.&lt;/p&gt;

&lt;h2 id=&#34;unit-tests&#34;&gt;Unit tests&lt;/h2&gt;

&lt;p&gt;Last but not least, automatic testing of functions in isolation might
be what you&amp;rsquo;re looking for ! See the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/testing.html&#34;&gt;testing&lt;/a&gt; section and a list of
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#unit-testing&#34;&gt;test frameworks and libraries&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://successful-lisp.blogspot.com/p/httpsdrive.html&#34;&gt;&amp;ldquo;How to understand and use Common Lisp&amp;rdquo;&lt;/a&gt;, chap. 30, David Lamkins (book download from author&amp;rsquo;s site)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://malisper.me/debugging-lisp-part-1-recompilation/&#34;&gt;Malisper: debugging Lisp series&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://two-wrongs.com/debugging-common-lisp-in-slime.html&#34;&gt;Two Wrongs: debugging Common Lisp in Slime&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>One liner, Git from Lisp: commit every file of this repository</title>
      <link>/blog/one-liner-git-commit-files/</link>
      <pubDate>Tue, 04 Dec 2018 21:49:06 +0100</pubDate>
      
      <guid>/blog/one-liner-git-commit-files/</guid>
      <description>&lt;p&gt;Hey, pardon this very short post, it&amp;rsquo;s just for the pleasure of
blogging, and to balance the usual lengthy ones.&lt;/p&gt;

&lt;p&gt;I wanted to commit, one by one, every file of the current directory
(it&amp;rsquo;s useless, don&amp;rsquo;t ask).&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&#34;https://shinmera.github.io/legit/&#34;&gt;legit&lt;/a&gt; as the interface to
Git, and this one-liner:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(dolist (file (uiop:directory-files &amp;quot;./&amp;quot;))
   (legit:git-add :paths (pathname file))
   (legit:git-commit :files (pathname file) :message (format nil &amp;quot;add ~a&amp;quot; (file-namestring file))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I guessed the &lt;code&gt;:paths&lt;/code&gt; and &lt;code&gt;:files&lt;/code&gt; arguments with Slime&amp;rsquo;s command
argument list which appears in the modline, I wanted a function to
convert a &lt;code&gt;/full/path/file.cl&lt;/code&gt; to a name &lt;code&gt;file.cl&lt;/code&gt; and tried the
completion for &lt;code&gt;file-…&lt;/code&gt; and found the right thing without effort. I
saw on the complete documentation that &lt;code&gt;legit:commit&lt;/code&gt; wanted a
repository object as first argument, which makes sense, but
&lt;code&gt;legit:git-commit&lt;/code&gt; doesn&amp;rsquo;t and I just iterate on the current working
directory (btw change it in Slime with the &lt;code&gt;,cd&lt;/code&gt; command) so it was
shorter for me.&lt;/p&gt;

&lt;p&gt;Just a one liner.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oh my god, I didn&amp;rsquo;t know we can do this in Lisp !&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course we can :p&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Overview of Documentation Generators</title>
      <link>/blog/overview-of-documentation-generators/</link>
      <pubDate>Wed, 07 Nov 2018 18:34:11 +0100</pubDate>
      
      <guid>/blog/overview-of-documentation-generators/</guid>
      <description>

&lt;p&gt;I have a simple need: I&amp;rsquo;d like to generate an html documentation from
my code. What options do we have ?&lt;/p&gt;

&lt;p&gt;I searched for &amp;ldquo;documentation tool&amp;rdquo; on Quickdocs:
&lt;a href=&#34;http://quickdocs.org/search?q=documentation%20tool&#34;&gt;http://quickdocs.org/search?q=documentation%20tool&lt;/a&gt;, from which I
remove old ones (clod, qbook, manifest).&lt;/p&gt;

&lt;p&gt;I had two pure Lisp solutions working out of the box, two more are of
interest, and there&amp;rsquo;s another non-Lisp of interest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;update&lt;/strong&gt;: just found out that &lt;a href=&#34;http://quickdocs.org/qbook/&#34;&gt;qbook&lt;/a&gt;
(&lt;a href=&#34;https://github.com/lisp-mirror/qbook&#34;&gt;github mirror&lt;/a&gt;)is used for the
documentation of Fiveam, which is pretty nice:
&lt;a href=&#34;https://common-lisp.net/project/fiveam/docs/index.html&#34;&gt;https://common-lisp.net/project/fiveam/docs/index.html&lt;/a&gt; It can produce
html and latex. It uses docstrings and comments that start with 4
commas to structure the page
(&lt;a href=&#34;https://github.com/sionescu/fiveam/blob/master/src/suite.lisp&#34;&gt;exple in source&lt;/a&gt;
that gives
&lt;a href=&#34;https://common-lisp.net/project/fiveam/docs/Test_0020Suites.html&#34;&gt;this&lt;/a&gt;). Running
it has a lot of asdf deprecation warnings and it did not work out of
the box for me (&amp;ldquo;The slot IT.BESE.QBOOK::GENERATOR is unbound in the object&amp;rdquo;).&lt;/p&gt;

&lt;h2 id=&#34;codex&#34;&gt;Codex&lt;/h2&gt;

&lt;p&gt;Codex produces nice html but isn&amp;rsquo;t automatic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CommonDoc/codex&#34;&gt;https://github.com/CommonDoc/codex&lt;/a&gt; (by @eudoxia)&lt;/li&gt;
&lt;li&gt;example: &lt;a href=&#34;https://commondoc.github.io/codex/docs/tutorial.html&#34;&gt;https://commondoc.github.io/codex/docs/tutorial.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;input fromat: &lt;a href=&#34;http://commondoc.github.io/scriba/docs/reference.html&#34;&gt;scriba&lt;/a&gt; by default. No more format it seems.&lt;/li&gt;
&lt;li&gt;output: multiple html files.&lt;/li&gt;
&lt;li&gt;rendering: modern, colored, light, TOC on the side&lt;/li&gt;
&lt;li&gt;granularity: good&lt;/li&gt;
&lt;li&gt;link to CLHS: yes&lt;/li&gt;
&lt;li&gt;totally automatic: no (one needs to create the documentation structure in &lt;code&gt;manual.lisp&lt;/code&gt;, AFAIU).&lt;/li&gt;
&lt;li&gt;used in the wild: yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting started: write a simple &lt;code&gt;docs/manifest.lisp&lt;/code&gt; and &lt;code&gt;docs/manual.lisp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Am I mistaking ? It&amp;rsquo;s exclusively manual. We must supply every
function/generic function/method/class/macro to document in
&lt;code&gt;manual.lisp&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;coo&#34;&gt;Coo&lt;/h2&gt;

&lt;p&gt;Coo is a new tool in town, it works out of the box and it is actively developed !&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fisxoj/coo&#34;&gt;https://github.com/fisxoj/coo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fisxoj.github.io/coo/&#34;&gt;https://fisxoj.github.io/coo/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;input: docstrings in &lt;code&gt;rst&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;output: multiple html&lt;/li&gt;
&lt;li&gt;rendering: black &amp;amp; white, no TOC (active development)&lt;/li&gt;
&lt;li&gt;links to CLHS: yes, since yesterday :)&lt;/li&gt;
&lt;li&gt;granularity: doesn&amp;rsquo;t show class slots, doesn&amp;rsquo;t show generic functions.&lt;/li&gt;
&lt;li&gt;used in the wild: coo no, more probably cl-docutils.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on &lt;a href=&#34;https://github.com/willijar/cl-docutils&#34;&gt;cl-docutils&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Displays the functions&amp;rsquo; documentation following their order in source (or not ? I saw exceptions).&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(coo:document-system :my-system)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it produces html into &lt;code&gt;docs/&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;staple-doesn-t-work-on-debian-s-sbcl-1-2-4&#34;&gt;Staple (doesn&amp;rsquo;t work on Debian&amp;rsquo;s SBCL 1.2.4)&lt;/h2&gt;

&lt;p&gt;You may be familiar with Staple since it&amp;rsquo;s used by Shinmera in all his projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shinmera/staple&#34;&gt;https://github.com/Shinmera/staple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;output: html. The documentation string is plain text (no markup, rendered in a &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; tag).&lt;/li&gt;
&lt;li&gt;cross-references&lt;/li&gt;
&lt;li&gt;can use a template.&lt;/li&gt;
&lt;li&gt;more features than listed here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It doesn&amp;rsquo;t support SBCL 1.2.4, so my tests fell short (upgrading isn&amp;rsquo;t
100% smooth here). If you&amp;rsquo;re on SBCL &amp;gt;= 1.4.8 Staple is a good option.&lt;/p&gt;

&lt;h2 id=&#34;declt&#34;&gt;Declt&lt;/h2&gt;

&lt;p&gt;Declt has higher goals than &amp;ldquo;quick and easy&amp;rdquo; documentation generator.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/didierverna/declt&#34;&gt;https://github.com/didierverna/declt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.lrde.epita.fr/~didier/software/lisp/declt/&#34;&gt;https://www.lrde.epita.fr/~didier/software/lisp/declt/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;output: a &lt;code&gt;.texi&lt;/code&gt; file, that we can render into other formats (html, pdf).&lt;/li&gt;
&lt;li&gt;cross-references: yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It didn&amp;rsquo;t work out of the box (and had no explicit error information)
and it&amp;rsquo;s also too involved for my use case.&lt;/p&gt;

&lt;h2 id=&#34;documentation-tool-not-for-general-use&#34;&gt;Documentation-tool (not for general use)&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s the template used for Edi Weitz software, like Hunchentoot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://edicl.github.io/documentation-template/&#34;&gt;https://edicl.github.io/documentation-template/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;output: one html file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works, but it thinks you publish an edicl software and has some hardcoded &amp;ldquo;&lt;a href=&#34;http://weitz.de/files/…&amp;quot;&#34;&gt;http://weitz.de/files/…&amp;quot;&lt;/a&gt; urls.&lt;/p&gt;

&lt;h2 id=&#34;tinaa-unmaintained&#34;&gt;Tinaa (unmaintained)&lt;/h2&gt;

&lt;p&gt;I liked the output, but it didn&amp;rsquo;t work (asdf-related error), and it&amp;rsquo;s unmaintained (authors&amp;rsquo; words).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gwkkwg/tinaa&#34;&gt;https://github.com/gwkkwg/tinaa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/tinaa/documentation/index.html&#34;&gt;https://common-lisp.net/project/tinaa/documentation/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;output: html&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;h3 id=&#34;cl-domain-sphinx&#34;&gt;cl-domain (Sphinx)&lt;/h3&gt;

&lt;p&gt;Another excellent option is 40ants&amp;rsquo; cldomain, which builds on Python&amp;rsquo;s proven Sphinx:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CLDomain is an extension for the Sphinx documentation generation tool that allow sphinx to generate documentation for Common Lisp libraries. Documentation is extracted from the various entity’s documentation strings, loaded from ASDF systems and associated internal packages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They use it for they new projects since around 3 years now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/cldomain&#34;&gt;https://github.com/40ants/cldomain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://40ants.com/cldomain/&#34;&gt;http://40ants.com/cldomain/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;input: rst&lt;/li&gt;
&lt;li&gt;output: many html&lt;/li&gt;
&lt;li&gt;HyperSpec links: yes&lt;/li&gt;
&lt;li&gt;requirements: Python, pip&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;udate&lt;/em&gt; 2019-01-22: extended example.&lt;/p&gt;

&lt;p&gt;An example from &lt;a href=&#34;https://github.com/40ants/cl-hamcrest/blob/master/docs/source/matchers.rst&#34;&gt;cl-hamcrest&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we reference Lisp functions/methods/macros with RST directives:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;Object matchers
===============

This kind of matchers checks some sort of properties on an object, etc.

.. cl:package:: hamcrest/matchers

.. cl:macro:: has-plist-entries
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;they have RST docstrings, also with RST directives to include code blocks:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(def-has-macro
    has-plist-entries
    &amp;quot;Matches plist entries:

.. code-block:: common-lisp-repl

   TEST&amp;gt; (let ((obj &#39;(:foo :bar)))
           (assert-that obj
                        (has-plist-entries :foo \&amp;quot;bar\&amp;quot;
                                           :blah \&amp;quot;minor\&amp;quot;)))
     × Key :FOO has :BAR value, but \&amp;quot;bar\&amp;quot; was expected

This way you can test any number of plist&#39;s entries.&amp;quot;

    :check-obj-type (check-if-list object)
    :get-key-value (let ((key-value (getf object key &#39;absent)))
                      (when (eql key-value &#39;absent)
                          …
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;this produces a nice output (&lt;a href=&#34;http://40ants.com/cl-hamcrest/matchers.html&#34;&gt;here&lt;/a&gt;):&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;/cl-domain.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I&amp;rsquo;ll use and watch Coo !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>We now have comments. Thanks, Utterances !</title>
      <link>/blog/we-now-have-comments-thanks-utterances/</link>
      <pubDate>Thu, 25 Oct 2018 18:45:20 +0200</pubDate>
      
      <guid>/blog/we-now-have-comments-thanks-utterances/</guid>
      <description>&lt;p&gt;We just installed a comment system, and it isn&amp;rsquo;t Disqus ! We just
discovered &lt;a href=&#34;utterances&#34;&gt;https://utteranc.es/&lt;/a&gt;, a lightweight widget
based on Github issues. If it doesn&amp;rsquo;t find an issue corresponding to
the current article, it will create one and post your comment
there. Simple :) You dreamed of it ? They did it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>These Months in Common Lisp: Q3 2018</title>
      <link>/blog/these-months-in-common-lisp-q3-2018/</link>
      <pubDate>Sat, 06 Oct 2018 23:47:06 +0200</pubDate>
      
      <guid>/blog/these-months-in-common-lisp-q3-2018/</guid>
      <description>

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q1-2018/&#34;&gt;Q1 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q2-2018/&#34;&gt;Q2 2018&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;CLOS – the Common Lisp Cookbook (extensive rewrite)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://cybertiggyr.com/fmt/fmt.pdf&#34;&gt;Advanced Use of Lisp’s FORMAT Function (2004)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cs.fsu.edu/~cap5605/Luger_Supplementary_Text.pdf&#34;&gt;Book: Luger/Stubblefield, 2009; AI Algorithms, Data Structures, and Idioms in Prolog, Lisp, and Java (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/DalekBaldwin/on-lisp&#34;&gt;GitHub - DalekBaldwin/on-lisp: A modernized and annotated code companion to Paul Graham&amp;rsquo;s &amp;ldquo;On Lisp&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://joaotavora.github.io/sly/&#34;&gt;SLY User Manual, version 1.0.0-beta-2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;announcements&#34;&gt;Announcements&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/&#34;&gt;A new version of Common-Lisp.net has been launched!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://old.reddit.com/r/Common_Lisp/comments/9as489/a_new_quickdist_distribution_ultralisporg/&#34;&gt;A new quickdist distribution – Ultralisp.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://events.tymoon.eu/4&#34;&gt;Autumn Lisp Game Jam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.sbcl.org/all-news.html?1.4.12#1.4.12&#34;&gt;SBCL 1.4.12 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/emacs/comments/9j1ubb/next_browser_linux_port_campaign/&#34;&gt;Next Browser Linux Port Campaign&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://awesome-cl.com/&#34;&gt;awesome-cl.com (the website)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;jobs&#34;&gt;Jobs&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9gs1ew/we_are_still_looking_for_lispers_who_want_to_work/&#34;&gt;We are still looking for Lispers who want to work in AI (Toronto and around the world)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://vimeo.com/237947324&#34;&gt;Introducing Seed: An Interactive Software Environment in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/knobo/live-reload&#34;&gt;Live reload prototype for clack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gkbrk.com/2018/08/mastodon-bot-in-common-lisp/&#34;&gt;Mastodon Bot in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kkazuo/slack-client&#34;&gt;slack-client: Slack Real Time Messaging API Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sirherrbatka/cl-progress-bar/&#34;&gt;cl-progress-bar: Progress bars, just like in quicklisp!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shinmera/oxenfurt&#34;&gt;Shinmera/oxenfurt: A Common Lisp client library for the Oxford dictionary API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-univ-etc.blogspot.com/2018/09/ann-flight-recorder-robust-repl-logging.html&#34;&gt;flight-recorder - a robust REPL logging facility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/MegaLoler/Music&#34;&gt;Music: Music framework for musical expression in Common Lisp with a focus on music theory (built from scratch, on development)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/tovero/&#34;&gt;Tovero is a 3D modeling system for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/jgkamat/rmsbolt&#34;&gt;RMSBolt: See what your compiler is going inside of Emacs (has minimal support for Common Lisp)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fjames86/ftw&#34;&gt;ftw: Common Lisp Win32 GUI library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.michaelfiano.com/projects/pngload/&#34;&gt;pngload: A PNG (Portable Network Graphics) image format decoder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9g2ook/melbase_forked_and_actively_updated_versatile/&#34;&gt;mel-base - forked and actively updated versatile mail library for common lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/phoe/wordnet&#34;&gt;wordnet: Common Lisp interface to WordNet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9brkej/clvep_a_video_effects_processor/&#34;&gt;cl-vep: a video effects processor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wayback.archive.org/web/20180611080125/https://www.informatik.uni-kiel.de/%7Ewg/clicc.html&#34;&gt;CLiCC - The Common Lisp to C Compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/phoe/list-named-class&#34;&gt;LIST-NAMED-CLASS - name your CLOS classes with lists, not just symbols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.guerra-espacial.rufina.link/&#34;&gt;GUERRA-ESPACIAL: an implementation of the spacewar computer game in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/clive/&#34;&gt;Clive is a Common Lisp binding to Open Inventor with extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/phoe/lorem-ipsum/&#34;&gt;Lorem ipsum generator in portable Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tlikonen/cl-decimals&#34;&gt;tlikonen/cl-decimals: Decimal number parser and formatter package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tlikonen/cl-enchant&#34;&gt;tlikonen/cl-enchant: Common Lisp bindings for the Enchant spell-checker library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tlikonen/cl-general-accumulator&#34;&gt;tlikonen/cl-general-accumulator: General-purpose, extensible value accumulator library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cuichaox/dml&#34;&gt;Drawing UML diagram with Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/m3tti/slurm-cl&#34;&gt;slurm-cl - a web application framework for Common Lisp and single page applications.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;new releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cxxxr/lem/releases/tag/v1.4&#34;&gt;Lem v1.4 has been released with paredit-mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/froggey/Mezzano/releases/tag/demo4&#34;&gt;Common Lisp OS Mezzano – Demo 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/mito/pull/38&#34;&gt;Mito ORM: new deftable shortcut to create default initargs, accessors and metaclass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.didierverna.net/blog/index.php?post/2018/08/07/Quickref-open-sourced&#34;&gt;Quickref open-sourced - Didier Verna&amp;rsquo;s Sci-Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(re)discoveries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/shuffletron-lisp-music-player-for-the-terminal/&#34;&gt;Shuffletron, a Common Lisp Music Player for the terminal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sellout/quid-pro-quo&#34;&gt;quid-pro-quo: a contract programming library in the style of Eiffel’s Design by Contract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://successful-lisp.blogspot.com/p/httpsdrive.html&#34;&gt;Successful Lisp: How to Understand and Use Common Lisp (Book download from Author&amp;rsquo;s site)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://cram-system.org/doc/ide&#34;&gt;Cognitive Robot Abstract Machine = Common Lisp + ROS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mabragor/cl-yaclyaml&#34;&gt;cl-yaclyaml - a YaML processor (loader, not dumper)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://scymtym.github.io/esrap/&#34;&gt;Esrap - a packrat parser for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.common-lisp.net/gendl/gendl&#34;&gt;gendl - Generative Programming and Knowledge-based Engineering (KBE) system embedded in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/pcostanza/filtered-functions&#34;&gt;pcostanza/filtered-functions: an extension of CLOS generic function invocation that enables the use of arbitrary predicates for selecting and applying methods.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;articles&#34;&gt;Articles&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/&#34;&gt;A Road to Common Lisp / Steve Losh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.newresalhaider.com/post/common-treasure/&#34;&gt;Excavating a Common Treasure: Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://christophe.rhodes.io/notes/blog/posts/2018/first_riscy_steps/&#34;&gt;First RISCy Steps &amp;ndash; Porting SBCL to the RISC-V&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@mhkoji/my-pattern-to-write-a-web-application-in-common-lisp-3-86e79c5c3551&#34;&gt;My pattern to write a web application in Common Lisp (3)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;A new way of blogging about Common Lisp&#34;&gt;A new way of blogging about Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@glikson/going-serverless-from-common-lisp-and-cgi-to-aws-lambda-and-api-gateway-9fba46c84fb8&#34;&gt;Going Serverless: From Common LISP and CGI to AWS Lambda and API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/07/fun-with-macros-if-let/&#34;&gt;Fun with Macros: If-Let and When-Let / Steve Losh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://old.reddit.com/r/Common_Lisp/comments/99q37t/how_to_enable_reader_macros_throughout_a_project/&#34;&gt;How to enable reader macros throughout a project with ASDF&amp;rsquo;s package-inferred-system (E. Fukamachi)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://openresearch-repository.anu.edu.au/bitstream/1885/144603/1/Sorensen%20Thesis%202018.pdf&#34;&gt;Extempore - The design, implementation and application of a cyber-physical programming language, Andrew Sorensen, Thesis, 2018 (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9gjd0m/lisping_copyleft_a_close_reading_of_the_lisp_lgpl/&#34;&gt;https://www.ifosslr.org/ojs/ifosslr/article/view/75&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://m00natic.github.io/lisp/manual-jit.html&#34;&gt;Uniform Structured Syntax, Metaprogramming and Run-time Compilation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://z0ltan.wordpress.com/2018/08/04/simple-expression-evaluator-comparison-between-haskell-rust-and-common-lisp/&#34;&gt;Simple expression evaluator comparison between Haskell, Rust, and Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/98s5zp/lisping_at_jpl/&#34;&gt;Lisping at JPL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/93v9cv/a_clon_guide/&#34;&gt;A Clon guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.radioeng.cz/fulltexts/2011/11_04_880_889.pdf&#34;&gt;Common LISP as Simulation Program (CLASP) of Electronic Circuits (2011) (pdf)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/criesbeck/cs325/&#34;&gt;Lisp code for Christopher Riesbeck&amp;rsquo;s cs325 AI course.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://old.reddit.com/r/Common_Lisp/comments/93g3p2/a_story_of_defun_games/&#34;&gt;A Story of (defun games ())&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;discussion&#34;&gt;Discussion&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9c94lu/what_applicationstasks_are_you_working_on_this/&#34;&gt;What are you working on this week ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8zvirn/cl_bad_for_native_guis_and_other_thoughts_on/&#34;&gt;CL bad for native GUIs? And other thoughts on first CL project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9er4mo/i_want_to_try_lisp_how_should_i_begin/&#34;&gt;I want to try Lisp, how should I begin?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9b7v56/what_lisp_dialect_for_real_world_applications/&#34;&gt;What lisp dialect for &amp;ldquo;real world&amp;rdquo; applications?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8w8cr1/what_do_commercial_lisps_offer_that_frees_dont/&#34;&gt;What do commercial Lisps offer that frees don&amp;rsquo;t?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9kiji7/which_nonclojure_lisp_to_learn_first/&#34;&gt;Which (non-Clojure) Lisp to learn first?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9k2vmi/can_cl_implement_clojures_keyword_as_function/&#34;&gt;Can CL implement Clojure&amp;rsquo;s keyword as function syntax?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9j7uld/why_cons_cells/&#34;&gt;Why cons cells?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;screencasts&#34;&gt;Screencasts&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/BL9MiiCcETM&#34;&gt;Little bits of Lisp - cl-autowrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/BL9MiiCcETM&#34;&gt;Lots of bits of Lisp - Generating Bindings to C Libraries &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=ygKXeLKhiTI&#34;&gt;Lots of bits of Lisp - Macros (2 hr episode)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/WEFLi-u7qyE&#34;&gt;Pushing Pixels with Lisp - Episode 59 - Basic Disolve Shaders&lt;/a&gt; (and more episodes !)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=z7V5BL6W3CA&#34;&gt;Common Lisp Study Group - Introduction to Screamer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=uRLgZCV4bOM&#34;&gt;Common Lisp Study Group: An Intro to SERIES&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=1zS46_HWRMo&#34;&gt;Daniel G Bobrow: Common LISP Object Standard 1987 (video 53min)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;common-lisp-vs&#34;&gt;Common Lisp VS &amp;hellip;&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8wdw2r/is_there_a_lisp_that_is_considered_excellent/&#34;&gt;Is there a Lisp that is considered &amp;ldquo;excellent&amp;rdquo; about error handling ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9lhbnx/lisp_dialect_survey/&#34;&gt;Lisp Dialect survey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9i5mmp/the_julia_challenge/&#34;&gt;the Julia challenge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9g07to/python_pitfalls/&#34;&gt;Python pitfalls ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/9lpssp/how_a_common_lisp_programmer_views_users_of_other/&#34;&gt;How a Common Lisp programmer views users of other languages (humor)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>CLOS Tutorial</title>
      <link>/blog/clos-tutorial/</link>
      <pubDate>Fri, 05 Oct 2018 19:37:35 +0200</pubDate>
      
      <guid>/blog/clos-tutorial/</guid>
      <description>

&lt;p&gt;&lt;em&gt;We just updated the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;CLOS page on the Common Lisp Cookbook&lt;/a&gt;. You should refer to it for updates.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;CLOS is the &amp;ldquo;Common Lisp Object System&amp;rdquo;, arguably one of the most
powerful object systems available in any language.&lt;/p&gt;

&lt;p&gt;Some of its features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it is &lt;strong&gt;dynamic&lt;/strong&gt;, making it a joy to work with in a Lisp REPL. For
example, changing a class definition will update the existing
objects, given certain rules which we have control upon.&lt;/li&gt;
&lt;li&gt;it supports &lt;strong&gt;multiple dispatch&lt;/strong&gt; and &lt;strong&gt;multiple inheritance&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;it is different from most object systems in that class and method
definitions are not tied together,&lt;/li&gt;
&lt;li&gt;it has excellent &lt;strong&gt;introspection&lt;/strong&gt; capabilities,&lt;/li&gt;
&lt;li&gt;it is provided by a &lt;strong&gt;meta-object protocol&lt;/strong&gt;, which provides a
standard interface to the CLOS, and can be used to create new object
systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The functionality belonging to this name was added to the Common Lisp
language between the publication of Steele&amp;rsquo;s first edition of &amp;ldquo;Common
Lisp, the Language&amp;rdquo; in 1984 and the formalization of the language as
an ANSI standard ten years later.&lt;/p&gt;

&lt;p&gt;This page aims to give a good understanding of how to use CLOS, but
only a brief introduction to the MOP.&lt;/p&gt;

&lt;p&gt;To learn the subjects in depth, you will need two books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.communitypicks.com/r/lisp/s/17592186046723-object-oriented-programming-in-common-lisp-a-programmer&#34;&gt;Object-Oriented Programming in Common Lisp: a Programmer&amp;rsquo;s Guide to CLOS&lt;/a&gt;, by Sonya Keene,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.communitypicks.com/r/lisp/s/17592186045709-the-art-of-the-metaobject-protocol&#34;&gt;the Art of the Metaobject Protocol&lt;/a&gt;, by Gregor Kiczales, Jim des Rivières et al.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But see also&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the introduction in &lt;a href=&#34;http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html&#34;&gt;Practical Common Lisp&lt;/a&gt; (online), by Peter Seibel.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node260.html#SECTION003200000000000000000&#34;&gt;Common Lisp, the Language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and for reference, the complete &lt;a href=&#34;https://clos-mop.hexstreamsoft.com/&#34;&gt;CLOS-MOP specifications&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#classes-and-instances&#34;&gt;Classes and instances&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#diving-in&#34;&gt;Diving in&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-objects-make-instance&#34;&gt;Creating objects (make-instance)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#slots&#34;&gt;Slots&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#a-function-that-always-works-slot-value&#34;&gt;A function that always works (slot-value)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#initial-and-default-values-initarg-initform&#34;&gt;Initial and default values (initarg, initform)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#getters-and-setters-accessor-reader-writer&#34;&gt;Getters and setters (accessor, reader, writer)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#class-vs-instance-slots&#34;&gt;Class VS instance slots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#slot-documentation&#34;&gt;Slot documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#slot-type&#34;&gt;Slot type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#find-class-class-name-class-of&#34;&gt;find-class, class-name, class-of&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#subclasses-and-inheritance&#34;&gt;Subclasses and inheritance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#multiple-inheritance&#34;&gt;Multiple inheritance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#redefining-and-changing-a-class&#34;&gt;Redefining and changing a class&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pretty-printing&#34;&gt;Pretty printing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#classes-of-traditional-lisp-types&#34;&gt;Classes of traditional lisp types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#introspection&#34;&gt;Introspection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#see-also&#34;&gt;See also&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#defclassstd-write-shorter-classes&#34;&gt;defclass/std: write shorter classes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#methods&#34;&gt;Methods&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#diving-in&#34;&gt;Diving in&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#generic-functions-defgeneric-defmethod&#34;&gt;Generic functions (defgeneric, defmethod)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#multimethods&#34;&gt;Multimethods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#controlling-setters-setf-ing-methods&#34;&gt;Controlling setters (setf-ing methods)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dispatch-mechanism-and-next-methods&#34;&gt;Dispatch mechanism and next methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#method-qualifiers-before-after-around&#34;&gt;Method qualifiers (before, after, around)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#other-method-combinations&#34;&gt;Other method combinations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#debugging-tracing-method-combination&#34;&gt;Debugging: tracing method combination&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mop&#34;&gt;MOP&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#metaclasses&#34;&gt;Metaclasses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#controlling-the-initialization-of-instances-initialize-instance&#34;&gt;Controlling the initialization of instances (initialize-instance)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;classes-and-instances&#34;&gt;Classes and instances&lt;/h1&gt;

&lt;h2 id=&#34;diving-in&#34;&gt;Diving in&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s dive in with an example showing class definition, creation of
objects, slot access, methods specialized for a given class, and
inheritance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)))

;; =&amp;gt; #&amp;lt;STANDARD-CLASS PERSON&amp;gt;

(defvar p1 (make-instance &#39;person :name &amp;quot;me&amp;quot; ))
;;                                 ^^^^ initarg
;; =&amp;gt; #&amp;lt;PERSON {1006234593}&amp;gt;

(name p1)
;;^^^ accessor
;; =&amp;gt; &amp;quot;me&amp;quot;

(lisper p1)
;; =&amp;gt; nil
;;    ^^ initform (slot unbound by default)

(setf (lisper p1) t)


(defclass child (person)
  ())

(defclass child (person)
  ((can-walk-p
     :accessor can-walk-p
     :initform t)))
;; #&amp;lt;STANDARD-CLASS CHILD&amp;gt;

(can-walk-p (make-instance &#39;child))
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;defining-classes-defclass&#34;&gt;Defining classes (defclass)&lt;/h2&gt;

&lt;p&gt;The macro used for defining new data types in CLOS is &lt;code&gt;defclass&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We used it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us a CLOS type (or class) called &lt;code&gt;person&lt;/code&gt; and two slots,
named &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;lisper&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(class-of p1)
#&amp;lt;STANDARD-CLASS PERSON&amp;gt;

(type-of p1)
PERSON
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The general form of &lt;code&gt;defclass&lt;/code&gt; is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defclass &amp;lt;class-name&amp;gt; (list of super classes)
  ((slot-1
     :slot-option slot-argument)
   (slot-2, etc))
  (:optional-class-option
   :another-optional-class-option))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, our &lt;code&gt;person&lt;/code&gt; class doesn&amp;rsquo;t explicitely inherit from another class
(it gets the empty parentheses &lt;code&gt;()&lt;/code&gt;). However it still inherits by default from
the class &lt;code&gt;t&lt;/code&gt; and from &lt;code&gt;standard-object&lt;/code&gt;. See below under
&amp;ldquo;inheritance&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;We could write a minimal class definition without slots options like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass point ()
  (x y z))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or even without slots specificiers: &lt;code&gt;(defclass point () ())&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;creating-objects-make-instance&#34;&gt;Creating objects (make-instance)&lt;/h2&gt;

&lt;p&gt;We create instances of a class with &lt;code&gt;make-instance&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar p1 (make-instance &#39;person :name &amp;quot;me&amp;quot; ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is generally good practice to define a constructor:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun make-person (name &amp;amp;key lisper)
  (make-instance &#39;person :name name :lisper lisper))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This has the direct advantage that you can control the required
arguments. You should now export the constructor from your package and
not the class itself.&lt;/p&gt;

&lt;h2 id=&#34;slots&#34;&gt;Slots&lt;/h2&gt;

&lt;h3 id=&#34;a-function-that-always-works-slot-value&#34;&gt;A function that always works (slot-value)&lt;/h3&gt;

&lt;p&gt;The function to access any slot anytime is &lt;code&gt;(slot-value &amp;lt;object&amp;gt; &amp;lt;slot-name&amp;gt;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Given our &lt;code&gt;point&lt;/code&gt; class above, which didn&amp;rsquo;t define any slot accessors:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar pt (make-instance &#39;point))

(inspect pt)
The object is a STANDARD-OBJECT of type POINT.
0. X: &amp;quot;unbound&amp;quot;
1. Y: &amp;quot;unbound&amp;quot;
2. Z: &amp;quot;unbound&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We got an object of type &lt;code&gt;POINT&lt;/code&gt;, but &lt;strong&gt;slots are unbound by
default&lt;/strong&gt;: trying to access them will raise an &lt;code&gt;UNBOUND-SLOT&lt;/code&gt;
condition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(slot-value pt &#39;x) ;; =&amp;gt; condition: the slot is unbound
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;slot-value&lt;/code&gt; is &lt;code&gt;setf&lt;/code&gt;-able:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (slot-value pt &#39;x) 1)
(slot-value pt &#39;x) ;; =&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;initial-and-default-values-initarg-initform&#34;&gt;Initial and default values (initarg, initform)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:initarg :foo&lt;/code&gt; is the keyword we can pass to &lt;code&gt;make-instance&lt;/code&gt; to
give a value to this slot:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-instance &#39;person :name &amp;quot;me&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(again: slots are unbound by default)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:initform &amp;lt;val&amp;gt;&lt;/code&gt; is the &lt;em&gt;default value&lt;/em&gt; in case we didn&amp;rsquo;t specify
an initarg.  This form is evaluated each time it&amp;rsquo;s needed, in the
lexical environment of the &lt;code&gt;defclass&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes we see the following trick to clearly require a slot:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass foo ()
    ((a
      :initarg :a
      :initform (error &amp;quot;you didn&#39;t supply an initial value for slot a&amp;quot;))))
;; #&amp;lt;STANDARD-CLASS FOO&amp;gt;

(make-instance &#39;foo) ;; =&amp;gt; enters the debugger.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;getters-and-setters-accessor-reader-writer&#34;&gt;Getters and setters (accessor, reader, writer)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:accessor foo&lt;/code&gt;: an accessor is both a &lt;strong&gt;getter&lt;/strong&gt; and a
&lt;strong&gt;setter&lt;/strong&gt;. Its argument is a name that will become a &lt;strong&gt;generic
function&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(name p1) ;; =&amp;gt; &amp;quot;me&amp;quot;

(type-of #&#39;name)
STANDARD-GENERIC-FUNCTION
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:reader&lt;/code&gt; and &lt;code&gt;:writer&lt;/code&gt; do what you expect. Only the &lt;code&gt;:writer&lt;/code&gt; is &lt;code&gt;setf&lt;/code&gt;-able.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don&amp;rsquo;t specify any of these, you can still use &lt;code&gt;slot-value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can give a slot more than one &lt;code&gt;:accessor&lt;/code&gt;, &lt;code&gt;:reader&lt;/code&gt; or &lt;code&gt;:initarg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We introduce two macros to make the access to slots shorter in some situations:&lt;/p&gt;

&lt;p&gt;1- &lt;code&gt;with-slots&lt;/code&gt; allows to abbreviate several calls to slot-value. The
first argument is a list of slot names. The second argument evaluates
to a CLOS instance. This is followed by optional declarations and an
implicit &lt;code&gt;progn&lt;/code&gt;. Lexically during the evaluation of the body, an
access to any of these names as a variable is equivalent to accessing
the corresponding slot of the instance with &lt;code&gt;slot-value&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-slots (name lisper)
    c1
  (format t &amp;quot;got ~a, ~a~&amp;amp;&amp;quot; name lisper))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-slots ((n name)
             (l lisper))
    c1
  (format t &amp;quot;got ~a, ~a~&amp;amp;&amp;quot; n l))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;2- &lt;code&gt;with-accessors&lt;/code&gt; is equivalent, but instead of a list of slots it
takes a list of accessor functions. Any reference to the variable
inside the macro is equivalent to a call to the accessor function.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-accessors ((name        name)
                  ^^variable  ^^accessor
                 (lisper lisper))
            p1
          (format t &amp;quot;name: ~a, lisper: ~a&amp;quot; name lisper))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;class-vs-instance-slots&#34;&gt;Class VS instance slots&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:allocation&lt;/code&gt; specifies whether this slot is &lt;em&gt;local&lt;/em&gt; or &lt;em&gt;shared&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a slot is &lt;em&gt;local&lt;/em&gt; by default, that means it can be different for each instance of the class. In that case &lt;code&gt;:allocation&lt;/code&gt; equals &lt;code&gt;:instance&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;a &lt;em&gt;shared&lt;/em&gt; slot will always be equal for all instances of the
class. We set it with &lt;code&gt;:allocation :class&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following example, note how changing the value of the class
slot &lt;code&gt;species&lt;/code&gt; of &lt;code&gt;p2&lt;/code&gt; affects all instances of the
class (whether or not those instances exist yet).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name :initarg :name :accessor name)
   (species
      :initform &#39;homo-sapiens
      :accessor species
      :allocation :class)))

;; Note that the slot &amp;quot;lisper&amp;quot; was removed in existing instances.
(inspect p1)
;; The object is a STANDARD-OBJECT of type PERSON.
;; 0. NAME: &amp;quot;me&amp;quot;
;; 1. SPECIES: HOMO-SAPIENS
;; &amp;gt; q

(defvar p2 (make-instance &#39;person))

(species p1)
(species p2)
;; HOMO-SAPIENS

(setf (species p2) &#39;homo-numericus)
;; HOMO-NUMERICUS

(species p1)
;; HOMO-NUMERICUS

(species (make-instance &#39;person))
;; HOMO-NUMERICUS

(let ((temp (make-instance &#39;person)))
    (setf (species temp) &#39;homo-lisper))
;; HOMO-LISPER
(species (make-instance &#39;person))
;; HOMO-LISPER
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;slot-documentation&#34;&gt;Slot documentation&lt;/h3&gt;

&lt;p&gt;Each slot accepts one &lt;code&gt;:documentation&lt;/code&gt; option.&lt;/p&gt;

&lt;h3 id=&#34;slot-type&#34;&gt;Slot type&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;:type&lt;/code&gt; slot option may not do the job you expect it does. If you
are new to the CLOS, we suggest you skip this section and use your own
constructors to manually check slot types.&lt;/p&gt;

&lt;p&gt;Indeed, whether slot types are being checked or not is undefined. See the &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/m_defcla.htm#defclass&#34;&gt;Hyperspec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Few implementations will do it. Clozure CL does it, SBCL does it when
safety is high (&lt;code&gt;(declaim (optimize safety))&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To do it otherwise, see &lt;a href=&#34;https://stackoverflow.com/questions/51723992/how-to-force-slots-type-to-be-checked-during-make-instance&#34;&gt;this Stack-Overflow answer&lt;/a&gt;, and see also &lt;a href=&#34;https://github.com/sellout/quid-pro-quo&#34;&gt;quid-pro-quo&lt;/a&gt;, a contract programming library.&lt;/p&gt;

&lt;h2 id=&#34;find-class-class-name-class-of&#34;&gt;find-class, class-name, class-of&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find-class &#39;point)
;; #&amp;lt;STANDARD-CLASS POINT 275B78DC&amp;gt;

(class-name (find-class &#39;point))
;; POINT

(class-of my-point)
;; #&amp;lt;STANDARD-CLASS POINT 275B78DC&amp;gt;

(typep my-point (class-of my-point))
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;CLOS classes are also instances of a CLOS class, and we can find out
what that class is, as in the example below:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(class-of (class-of my-point))
;; #&amp;lt;STANDARD-CLASS STANDARD-CLASS 20306534&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;Note&lt;/u&gt;: this is your first introduction to the MOP. You don&amp;rsquo;t need that to get started !&lt;/p&gt;

&lt;p&gt;The object &lt;code&gt;my-point&lt;/code&gt; is an instance of the class named &lt;code&gt;point&lt;/code&gt;, and the
class named &lt;code&gt;point&lt;/code&gt; is itself an instance of the class named
&lt;code&gt;standard-class&lt;/code&gt;. We say that the class named &lt;code&gt;standard-class&lt;/code&gt; is
the &lt;em&gt;metaclass&lt;/em&gt; (i.e. the class of the class) of
&lt;code&gt;my-point&lt;/code&gt;. We can make good uses of metaclasses, as we&amp;rsquo;ll see later.&lt;/p&gt;

&lt;h2 id=&#34;subclasses-and-inheritance&#34;&gt;Subclasses and inheritance&lt;/h2&gt;

&lt;p&gt;As illustrated above, &lt;code&gt;child&lt;/code&gt; is a subclass of &lt;code&gt;person&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All objects inherit from the class &lt;code&gt;standard-object&lt;/code&gt; and &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every child instance is also an instance of &lt;code&gt;person&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(type-of c1)
;; CHILD

(subtypep (type-of c1) &#39;person)
;; T

(ql:quickload &amp;quot;closer-mop&amp;quot;)
;; ...

(closer-mop:subclassp (class-of c1) &#39;person)
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/pcostanza/closer-mop&#34;&gt;closer-mop&lt;/a&gt; library is &lt;em&gt;the&lt;/em&gt;
portable way to do CLOS/MOP operations.&lt;/p&gt;

&lt;p&gt;A subclass inherits all of its parents slots, and it can override any
of their slot options. Common Lisp makes this process dynamic, great
for REPL session, and we can even control parts of it (like, do
something when a given slot is removed/updated/added, etc).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;class precedence list&lt;/strong&gt; of a &lt;code&gt;child&lt;/code&gt; is thus:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;child &amp;lt;- person &amp;lt;-- standard-object &amp;lt;- t
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which we can get with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(closer-mop:class-precedence-list (class-of c1))
;; (#&amp;lt;standard-class child&amp;gt;
;;  #&amp;lt;standard-class person&amp;gt;
;;  #&amp;lt;standard-class standard-object&amp;gt;
;;  #&amp;lt;sb-pcl::slot-class sb-pcl::slot-object&amp;gt;
;;  #&amp;lt;sb-pcl:system-class t&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, the &lt;strong&gt;direct superclass&lt;/strong&gt; of a &lt;code&gt;child&lt;/code&gt; is only:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(closer-mop:class-direct-superclasses (class-of c1))
;; (#&amp;lt;standard-class person&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can further inspect our classes with
&lt;code&gt;class-direct-[subclasses, slots, default-initargs]&lt;/code&gt; and many more functions.&lt;/p&gt;

&lt;p&gt;How slots are combined follows some rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:accessor&lt;/code&gt; and &lt;code&gt;:reader&lt;/code&gt; are combined by the &lt;strong&gt;union&lt;/strong&gt; of accessors
and readers from all the inherited slots.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;:initarg&lt;/code&gt;: the &lt;strong&gt;union&lt;/strong&gt; of initialization arguments from all the
inherited slots.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;:initform&lt;/code&gt;: we get &lt;strong&gt;the most specific&lt;/strong&gt; default initial value
form, i.e. the first &lt;code&gt;:initform&lt;/code&gt; for that slot in the precedence
list.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;:allocation&lt;/code&gt; is not inherited. It is controlled solely by the class
being defined and defaults to &lt;code&gt;:instance&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last but not least, be warned that inheritance is fairly easy to
misuse, and multiple inheritance is multiply so, so please take a
little care. Ask yourself whether &lt;code&gt;foo&lt;/code&gt; really wants to inherit from
&lt;code&gt;bar&lt;/code&gt;, or whether instances of &lt;code&gt;foo&lt;/code&gt; want a slot containing a &lt;code&gt;bar&lt;/code&gt;. A
good general guide is that if &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; are &amp;ldquo;same sort of thing&amp;rdquo;
then it&amp;rsquo;s correct to mix them together by inheritance, but if they&amp;rsquo;re
really separate concepts then you should use slots to keep them apart.&lt;/p&gt;

&lt;h2 id=&#34;multiple-inheritance&#34;&gt;Multiple inheritance&lt;/h2&gt;

&lt;p&gt;CLOS supports multiple inheritance.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun baby (child person)
  ())
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first class on the list of parent classes is the most specific
one, &lt;code&gt;child&lt;/code&gt;&amp;rsquo;s slots will take precedence over the &lt;code&gt;person&lt;/code&gt;&amp;rsquo;s&lt;/p&gt;

&lt;p&gt;TODO (but
remember how slots are merged).&lt;/p&gt;

&lt;h2 id=&#34;redefining-and-changing-a-class&#34;&gt;Redefining and changing a class&lt;/h2&gt;

&lt;p&gt;This section briefly covers two topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;redefinition of an existing class, which you might already have done
by following our code snippets, and what we do naturally during
development, and&lt;/li&gt;
&lt;li&gt;changing an instance of one class into an instance of another,
a powerful feature of CLOS that you&amp;rsquo;ll probably won&amp;rsquo;t use very often.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;rsquo;ll gloss over the details. Suffice it to say that everything&amp;rsquo;s
configurable by implementing methods exposed by the MOP.&lt;/p&gt;

&lt;p&gt;To redefine a class, simply evaluate a new &lt;code&gt;defclass&lt;/code&gt; form. This then
takes the place of the old definition, the existing class object is
updated, and &lt;strong&gt;all instances of the class&lt;/strong&gt; (and, recursively, its
subclasses) &lt;strong&gt;are lazily updated to reflect the new definition&lt;/strong&gt;. You don&amp;rsquo;t
have to recompile anything other than the new &lt;code&gt;defclass&lt;/code&gt;, nor to
invalidate any of your objects. Think about it for a second: this is awesome !&lt;/p&gt;

&lt;p&gt;For example, with our &lt;code&gt;person&lt;/code&gt; class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)))

(setf p1 (make-instance &#39;person :name &amp;quot;me&amp;quot; ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Changing, adding, removing slots,&amp;hellip;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lisper p1)
;; NIL

(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform t        ;; &amp;lt;-- from nil to t
    :accessor lisper)))

(lisper p1)
;; NIL (of course!)

(lisper (make-instance &#39;person :name &amp;quot;You&amp;quot;))
;; T

(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)
   (age
    :initarg :arg
    :initform 18
    :accessor age)))

(age p1)
;; =&amp;gt; slot unbound error. This is different from &amp;quot;slot missing&amp;quot;:

(slot-value p1 &#39;bwarf)
;; =&amp;gt; &amp;quot;the slot bwarf is missing from the object #&amp;lt;person…&amp;gt;&amp;quot;

(setf (age p1) 30)
(age p1) ;; =&amp;gt; 30

(defclass person ()
  ((name
    :initarg :name
    :accessor name)))

(slot-value p1 &#39;lisper) ;; =&amp;gt; slot lisper is missing.
(lisper p1) ;; =&amp;gt; there is no applicable method for the generic function lisper when called with arguments #(lisper).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To change the class of an instance, use &lt;code&gt;change-class&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(change-class p1 &#39;child)
;; we can also set slots of the new class:
(change-class p1 &#39;child :can-walk-p nil)

(class-of p1)
;; #&amp;lt;STANDARD-CLASS CHILD&amp;gt;

(can-walk-p p1)
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the above example, I became a &lt;code&gt;child&lt;/code&gt;, and I inherited the &lt;code&gt;can-walk-p&lt;/code&gt; slot, which is true by default.&lt;/p&gt;

&lt;h2 id=&#34;pretty-printing&#34;&gt;Pretty printing&lt;/h2&gt;

&lt;p&gt;Everytime we printed an object so far we got an output like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;PERSON {1006234593}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which doesn&amp;rsquo;t say much.&lt;/p&gt;

&lt;p&gt;What if we want to show more information ? Something like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;PERSON me lisper: t&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty printing is done by specializing the generic &lt;code&gt;print-object&lt;/code&gt; method for this class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod print-object ((obj person) stream)
      (print-unreadable-object (obj stream :type t)
        (with-accessors ((name name)
                         (lisper lisper))
            obj
          (format stream &amp;quot;~a, lisper: ~a&amp;quot; name lisper))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It gives:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;p1
;; #&amp;lt;PERSON me, lisper: T&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;print-unreadable-object&lt;/code&gt; prints the &lt;code&gt;#&amp;lt;...&amp;gt;&lt;/code&gt;, that says to the reader
that this object can not be read back in. Its &lt;code&gt;:type t&lt;/code&gt; argument asks
to print the object-type prefix, that is, &lt;code&gt;PERSON&lt;/code&gt;. Without it, we get
&lt;code&gt;#&amp;lt;me, lisper: T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We used the &lt;code&gt;with-accessors&lt;/code&gt; macro, but of course for simple cases this is enough:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod print-object ((obj person) stream)
  (print-unreadable-object (obj stream :type t)
    (format stream &amp;quot;~a, lisper: ~a&amp;quot; (name obj) (lisper obj))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Caution: trying to access a slot that is not bound by default will
lead to an error. Use &lt;code&gt;slot-boundp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For reference, the following reproduces the default behaviour:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod print-object ((obj person) stream)
  (print-unreadable-object (obj stream :type t :identity t)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, &lt;code&gt;:identity&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; prints the &lt;code&gt;{1006234593}&lt;/code&gt; address.&lt;/p&gt;

&lt;h2 id=&#34;classes-of-traditional-lisp-types&#34;&gt;Classes of traditional lisp types&lt;/h2&gt;

&lt;p&gt;Where we approach that we don&amp;rsquo;t need CLOS objects to use CLOS.&lt;/p&gt;

&lt;p&gt;Generously, the functions introduced in the last section also work on
lisp objects which are &lt;u&gt;not&lt;/u&gt; CLOS instances:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find-class &#39;symbol)
;; #&amp;lt;BUILT-IN-CLASS SYMBOL&amp;gt;
(class-name *)
;; SYMBOL
(eq ** (class-of &#39;symbol))
;; T
(class-of ***)
;; #&amp;lt;STANDARD-CLASS BUILT-IN-CLASS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We see here that symbols are instances of the system class
&lt;code&gt;symbol&lt;/code&gt;. This is one of 75 cases in which the language requires a
class to exist with the same name as the corresponding lisp
type. Many of these cases are concerned with CLOS itself (for
example, the correspondence between the type &lt;code&gt;standard-class&lt;/code&gt; and
the CLOS class of that name) or with the condition system (which
might or might not be built using CLOS classes in any given
implementation). However, 33 correspondences remain relating to
&amp;ldquo;traditional&amp;rdquo; lisp types:&lt;/p&gt;

&lt;p&gt;|&lt;code&gt;array&lt;/code&gt;|&lt;code&gt;hash-table&lt;/code&gt;|&lt;code&gt;readtable&lt;/code&gt;|
|&lt;code&gt;bit-vector&lt;/code&gt;|&lt;code&gt;integer&lt;/code&gt;|&lt;code&gt;real&lt;/code&gt;|
|&lt;code&gt;broadcast-stream&lt;/code&gt;|&lt;code&gt;list&lt;/code&gt;|&lt;code&gt;sequence&lt;/code&gt;|
|&lt;code&gt;character&lt;/code&gt;|&lt;code&gt;logical-pathname&lt;/code&gt;|&lt;code&gt;stream&lt;/code&gt;|
|&lt;code&gt;complex&lt;/code&gt;|&lt;code&gt;null&lt;/code&gt;|&lt;code&gt;string&lt;/code&gt;|
|&lt;code&gt;concatenated-stream&lt;/code&gt;|&lt;code&gt;number&lt;/code&gt;|&lt;code&gt;string-stream&lt;/code&gt;|
|&lt;code&gt;cons&lt;/code&gt;|&lt;code&gt;package&lt;/code&gt;|&lt;code&gt;symbol&lt;/code&gt;|
|&lt;code&gt;echo-stream&lt;/code&gt;|&lt;code&gt;pathname&lt;/code&gt;|&lt;code&gt;synonym-stream&lt;/code&gt;|
|&lt;code&gt;file-stream&lt;/code&gt;|&lt;code&gt;random-state&lt;/code&gt;|&lt;code&gt;t&lt;/code&gt;|
|&lt;code&gt;float&lt;/code&gt;|&lt;code&gt;ratio&lt;/code&gt;|&lt;code&gt;two-way-stream&lt;/code&gt;|
|&lt;code&gt;function&lt;/code&gt;|&lt;code&gt;rational&lt;/code&gt;|&lt;code&gt;vector&lt;/code&gt;|&lt;/p&gt;

&lt;p&gt;Note that not all &amp;ldquo;traditional&amp;rdquo; lisp types are included in this
list. (Consider: &lt;code&gt;atom&lt;/code&gt;, &lt;code&gt;fixnum&lt;/code&gt;, &lt;code&gt;short-float&lt;/code&gt;, and any type not
denoted by a symbol.)&lt;/p&gt;

&lt;p&gt;The presence of &lt;code&gt;t&lt;/code&gt; is interesting. Just as every lisp
object is of type &lt;code&gt;t&lt;/code&gt;, every lisp object is also a member
of the class named &lt;code&gt;t&lt;/code&gt;. This is a simple example of
membership of more then one class at a time, and it brings into
question the issue of &lt;em&gt;inheritance&lt;/em&gt;, which we will consider
in some detail later.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find-class t)
;; #&amp;lt;BUILT-IN-CLASS T 20305AEC&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In addition to classes corresponding to lisp types, there is also a
    CLOS class for every structure type you define:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct foo)
FOO

(class-of (make-foo))
;; #&amp;lt;STRUCTURE-CLASS FOO 21DE8714&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The metaclass of a &lt;code&gt;structure-object&lt;/code&gt; is the class
    &lt;code&gt;structure-class&lt;/code&gt;. It is implementation-dependent whether
    the metaclass of a &amp;ldquo;traditional&amp;rdquo; lisp object is
    &lt;code&gt;standard-class&lt;/code&gt;, &lt;code&gt;structure-class&lt;/code&gt;, or
    &lt;code&gt;built-in-class&lt;/code&gt;. Restrictions:&lt;/p&gt;

&lt;p&gt;|&lt;code&gt;built-in-class&lt;/code&gt;| May not use &lt;code&gt;make-instance&lt;/code&gt;, may not use &lt;code&gt;slot-value&lt;/code&gt;, may not use &lt;code&gt;defclass&lt;/code&gt; to modify, may not create subclasses.|
|&lt;code&gt;structure-class&lt;/code&gt;| May not use &lt;code&gt;make-instance&lt;/code&gt;, might work with &lt;code&gt;slot-value&lt;/code&gt; (implementation-dependent). Use &lt;code&gt;defstruct&lt;/code&gt; to subclass application structure types. Consequences of modifying an existing &lt;code&gt;structure-class&lt;/code&gt; are undefined: full recompilation may be necessary.|
|&lt;code&gt;standard-class&lt;/code&gt;|None of these restrictions.|&lt;/p&gt;

&lt;h2 id=&#34;introspection&#34;&gt;Introspection&lt;/h2&gt;

&lt;p&gt;we already saw some introspection functions.&lt;/p&gt;

&lt;p&gt;Your best option is to discover the
&lt;a href=&#34;https://github.com/pcostanza/closer-mop&#34;&gt;closer-mop&lt;/a&gt; libray and to
keep the &lt;a href=&#34;https://clos-mop.hexstreamsoft.com/&#34;&gt;CLOS &amp;amp; MOP specifications&lt;/a&gt; at
hand.&lt;/p&gt;

&lt;p&gt;More functions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;closer-mop:class-default-initargs
closer-mop:class-direct-default-initargs
closer-mop:class-direct-slots
closer-mop:class-direct-subclasses
closer-mop:class-direct-superclasses
closer-mop:class-precedence-list
closer-mop:class-slots
closer-mop:classp
closer-mop:extract-lambda-list
closer-mop:extract-specializer-names
closer-mop:generic-function-argument-precedence-order
closer-mop:generic-function-declarations
closer-mop:generic-function-lambda-list
closer-mop:generic-function-method-class
closer-mop:generic-function-method-combination
closer-mop:generic-function-methods
closer-mop:generic-function-name
closer-mop:method-combination
closer-mop:method-function
closer-mop:method-generic-function
closer-mop:method-lambda-list
closer-mop:method-specializers
closer-mop:slot-definition
closer-mop:slot-definition-allocation
closer-mop:slot-definition-initargs
closer-mop:slot-definition-initform
closer-mop:slot-definition-initfunction
closer-mop:slot-definition-location
closer-mop:slot-definition-name
closer-mop:slot-definition-readers
closer-mop:slot-definition-type
closer-mop:slot-definition-writers
closer-mop:specializer-direct-generic-functions
closer-mop:specializer-direct-methods
closer-mop:standard-accessor-method
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;h3 id=&#34;defclass-std-write-shorter-classes&#34;&gt;defclass/std: write shorter classes&lt;/h3&gt;

&lt;p&gt;The library &lt;a href=&#34;https://github.com/EuAndreh/defclass-std&#34;&gt;defclass/std&lt;/a&gt;
provides a macro to write shorter &lt;code&gt;defclass&lt;/code&gt; forms.&lt;/p&gt;

&lt;p&gt;By default, it adds an accessor, an initarg and an initform to &lt;code&gt;nil&lt;/code&gt; to your slots definition:&lt;/p&gt;

&lt;p&gt;This:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass/std example ()
  ((slot1 slot2 slot3)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;expands to:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass example ()
  ((slot1
    :accessor slot1
    :initarg :slot1
    :initform nil)
   (slot2
     :accessor slot2
     :initarg :slot2
     :initform nil)
   (slot3
     :accessor slot3
     :initarg :slot3
     :initform nil)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It does much more and it is very flexible, however it is seldom used
by the Common Lisp community: use at your own risks©.&lt;/p&gt;

&lt;h1 id=&#34;methods&#34;&gt;Methods&lt;/h1&gt;

&lt;h2 id=&#34;diving-in-1&#34;&gt;Diving in&lt;/h2&gt;

&lt;p&gt;Recalling our &lt;code&gt;person&lt;/code&gt; and &lt;code&gt;child&lt;/code&gt; classes from the beginning:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass person ()
  ((name
    :initarg :name
    :accessor name)))
;; =&amp;gt; #&amp;lt;STANDARD-CLASS PERSON&amp;gt;

(defclass child (person)
  ())
;; #&amp;lt;STANDARD-CLASS CHILD&amp;gt;

(setf p1 (make-instance &#39;person :name &amp;quot;me&amp;quot;))
(setf c1 (make-instance &#39;child :name &amp;quot;Alice&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Below we create methods, we specialize them, we use method combination
(before, after, around), and qualifiers.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod greet (obj)
  (format t &amp;quot;Are you a person ? You are a ~a.~&amp;amp;&amp;quot; (type-of obj)))
;; style-warning: Implicitly creating new generic function common-lisp-user::greet.
;; #&amp;lt;STANDARD-METHOD GREET (t) {1008EE4603}&amp;gt;

(greet :anything)
;; Are you a person ? You are a KEYWORD.
;; NIL
(greet p1)
;; Are you a person ? You are a PERSON.

(defgeneric greet (obj)
  (:documentation &amp;quot;say hello&amp;quot;))
;; STYLE-WARNING: redefining COMMON-LISP-USER::GREET in DEFGENERIC
;; #&amp;lt;STANDARD-GENERIC-FUNCTION GREET (2)&amp;gt;

(defmethod greet ((obj person))
  (format t &amp;quot;Hello ~a !~&amp;amp;&amp;quot; (name obj)))
;; #&amp;lt;STANDARD-METHOD GREET (PERSON) {1007C26743}&amp;gt;

(greet p1) ;; =&amp;gt; &amp;quot;Hello me !&amp;quot;
(greet c1) ;; =&amp;gt; &amp;quot;Hello Alice !&amp;quot;

(defmethod greet ((obj child))
  (format t &amp;quot;ur so cute~&amp;amp;&amp;quot;))
;; #&amp;lt;STANDARD-METHOD GREET (CHILD) {1008F3C1C3}&amp;gt;

(greet p1) ;; =&amp;gt; &amp;quot;Hello me !&amp;quot;
(greet c1) ;; =&amp;gt; &amp;quot;ur so cute&amp;quot;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Method combination: before, after, around.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmethod greet :before ((obj person))
  (format t &amp;quot;-- before person~&amp;amp;&amp;quot;))
#&amp;lt;STANDARD-METHOD GREET :BEFORE (PERSON) {100C94A013}&amp;gt;

(greet p1)
;; -- before person
;; Hello me

(defmethod greet :before ((obj child))
  (format t &amp;quot;-- before child~&amp;amp;&amp;quot;))
;; #&amp;lt;STANDARD-METHOD GREET :BEFORE (CHILD) {100AD32A43}&amp;gt;
(greet c1)
;; -- before child
;; -- before person
;; ur so cute

(defmethod greet :after ((obj person))
  (format t &amp;quot;-- after person~&amp;amp;&amp;quot;))
;; #&amp;lt;STANDARD-METHOD GREET :AFTER (PERSON) {100CA2E1A3}&amp;gt;
(greet p1)
;; -- before person
;; Hello me
;; -- after person

(defmethod greet :after ((obj child))
  (format t &amp;quot;-- after child~&amp;amp;&amp;quot;))
;; #&amp;lt;STANDARD-METHOD GREET :AFTER (CHILD) {10075B71F3}&amp;gt;
(greet c1)
;; -- before child
;; -- before person
;; ur so cute
;; -- after person
;; -- after child

(defmethod greet :around ((obj child))
  (format t &amp;quot;Hello my dear~&amp;amp;&amp;quot;))
;; #&amp;lt;STANDARD-METHOD GREET :AROUND (CHILD) {10076658E3}&amp;gt;
(greet c1) ;; Hello my dear


;; call-next-method

(defmethod greet :around ((obj child))
  (format t &amp;quot;Hello my dear~&amp;amp;&amp;quot;)
  (when (next-method-p)
    (call-next-method)))
;; #&amp;lt;standard-method greet :around (child) {100AF76863}&amp;gt;

(greet c1)
;; Hello my dear
;; -- before child
;; -- before person
;; ur so cute
;; -- after person
;; -- after child

;;;;;;;;;;;;;;;;;
;; Adding in &amp;amp;key
;;;;;;;;;;;;;;;;;

;; In order to add &amp;quot;&amp;amp;key&amp;quot; to our generic method, we need to remove its definition first.
(fmakunbound &#39;greet)  ;; with Slime: C-c C-u (slime-undefine-function)
(defmethod greet ((obj person) &amp;amp;key talkative)
  (format t &amp;quot;Hello ~a~&amp;amp;&amp;quot; (name obj))
  (when talkative
    (format t &amp;quot;blah&amp;quot;)))

(defgeneric greet (obj &amp;amp;key &amp;amp;allow-other-keys)
  (:documentation &amp;quot;say hi&amp;quot;))

(defmethod greet (obj &amp;amp;key &amp;amp;allow-other-keys)
  (format t &amp;quot;Are you a person ? You are a ~a.~&amp;amp;&amp;quot; (type-of obj)))

(defmethod greet ((obj person) &amp;amp;key talkative &amp;amp;allow-other-keys)
  (format t &amp;quot;Hello ~a !~&amp;amp;&amp;quot; (name obj))
  (when talkative
    (format t &amp;quot;blah&amp;quot;)))

(greet p1 :talkative t) ;; ok
(greet p1 :foo t) ;; still ok


;;;;;;;;;;;;;;;;;;;;;;;

(defgeneric greet (obj)
  (:documentation &amp;quot;say hello&amp;quot;)
  (:method (obj)
    (format t &amp;quot;Are you a person ? You are a ~a~&amp;amp;.&amp;quot; (type-of obj)))
  (:method ((obj person))
    (format t &amp;quot;Hello ~a !~&amp;amp;&amp;quot; (name obj)))
  (:method ((obj child))
    (format t &amp;quot;ur so cute~&amp;amp;&amp;quot;)))

;;;;;;;;;;;;;;;;
;;; Specializers
;;;;;;;;;;;;;;;;

(defgeneric feed (obj meal-type)
  (:method (obj meal-type)
    (declare (ignorable meal-type))
    (format t &amp;quot;eating~&amp;amp;&amp;quot;)))

(defmethod feed (obj (meal-type (eql :dessert)))
    (declare (ignorable meal-type))
    (format t &amp;quot;mmh, dessert !~&amp;amp;&amp;quot;))

(feed c1 :dessert)
;; mmh, dessert !

(defmethod feed ((obj child) (meal-type (eql :soup)))
    (declare (ignorable meal-type))
    (format t &amp;quot;bwark~&amp;amp;&amp;quot;))

(feed p1 :soup)
;; eating
(feed c1 :soup)
;; bwark
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;generic-functions-defgeneric-defmethod&#34;&gt;Generic functions (defgeneric, defmethod)&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;generic function&lt;/code&gt; is a lisp function which is associated
with a set of methods and dispatches them when it&amp;rsquo;s invoked. All
the methods with the same function name belong to the same generic
function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;defmethod&lt;/code&gt; form is similar to a &lt;code&gt;defun&lt;/code&gt;. It associates a body of
code with a function name, but that body may only be executed if the
types of the arguments match the pattern declared by the lambda list.&lt;/p&gt;

&lt;p&gt;They can have optional, keyword and &lt;code&gt;&amp;amp;rest&lt;/code&gt; arguments.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;defgeneric&lt;/code&gt; form defines the generic function. If we write a
&lt;code&gt;defmethod&lt;/code&gt; without a corresponding &lt;code&gt;defgeneric&lt;/code&gt;, a generic function
is automatically created (see examples).&lt;/p&gt;

&lt;p&gt;It is generally a good idea to write the &lt;code&gt;defgeneric&lt;/code&gt;s. We can add a
default implementation and even some documentation.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric greet (obj)
  (:documentation &amp;quot;says hi&amp;quot;)
  (:method (obj)
    (format t &amp;quot;Hi&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The required parameters in the method&amp;rsquo;s lambda list may take one of
the following three forms:&lt;/p&gt;

&lt;p&gt;1- a simple variable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod greet (foo)
  ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This method can take any argument, it is always applicable.&lt;/p&gt;

&lt;p&gt;The variable &lt;code&gt;foo&lt;/code&gt; is bound to the corresponding argument value, as
usual.&lt;/p&gt;

&lt;p&gt;2- a variable and a &lt;strong&gt;specializer&lt;/strong&gt;, as in:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod greet ((foo person))
  ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, the variable &lt;code&gt;foo&lt;/code&gt; is bound to the corresponding
argument only if that argument is of specializer class &lt;code&gt;person&lt;/code&gt; &lt;em&gt;or a subclass&lt;/em&gt;,
like &lt;code&gt;child&lt;/code&gt; (indeed, a &amp;ldquo;child&amp;rdquo; is also a &amp;ldquo;person&amp;rdquo;).&lt;/p&gt;

&lt;p&gt;If any argument fails to match its
specializer then the method is not &lt;em&gt;applicable&lt;/em&gt; and it cannot be
executed with those arguments.We&amp;rsquo;ll get an error message like
&amp;ldquo;there is no applicable method for the generic function xxx when
called with arguments yyy&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only required parameters can be specialized&lt;/strong&gt;. We can&amp;rsquo;t specialize on optional &lt;code&gt;&amp;amp;key&lt;/code&gt; arguments.&lt;/p&gt;

&lt;p&gt;3- a variable and an &lt;strong&gt;eql specializer&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod feed ((obj child) (meal-type (eql :soup)))
    (declare (ignorable meal-type))
    (format t &amp;quot;bwark~&amp;amp;&amp;quot;))

(feed c1 :soup)
;; &amp;quot;bwark&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In place of a simple symbol (&lt;code&gt;:soup&lt;/code&gt;), the eql specializer can be any
lisp form. It is evaluated at the same time of the defmethod.&lt;/p&gt;

&lt;p&gt;You can define any number of methods with the same function name but
with different specializers, as long as the form of the lambda list is
&lt;em&gt;congruent&lt;/em&gt; with the shape of the generic function. The system chooses
the most &lt;em&gt;specific&lt;/em&gt; applicable method and executes its body. The most
specific method is the one whose specializers are nearest to the head
of the &lt;code&gt;class-precedence-list&lt;/code&gt; of the argument (classes on the left of
the lambda list are more specific). A method with specializers is more
specific to one without any.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It is an error to define a method with the same function name as
an ordinary function. If you really want to do that, use the
shadowing mechanism.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;To add or remove &lt;code&gt;keys&lt;/code&gt; or &lt;code&gt;rest&lt;/code&gt; arguments to an existing generic
method&amp;rsquo;s lambda list, you will need to delete its declaration with
&lt;code&gt;fmakunbound&lt;/code&gt; (or &lt;code&gt;C-c C-u&lt;/code&gt; (slime-undefine-function) with the
cursor on the function in Slime) and start again. Otherwise,
you&amp;rsquo;ll see:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;attempt to add the method
  #&amp;lt;STANDARD-METHOD NIL (#&amp;lt;STANDARD-CLASS CHILD&amp;gt;) {1009504233}&amp;gt;
to the generic function
  #&amp;lt;STANDARD-GENERIC-FUNCTION GREET (2)&amp;gt;;
but the method and generic function differ in whether they accept
&amp;amp;REST or &amp;amp;KEY arguments.
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Methods can be redefined (exactly as for ordinary functions).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The order in which methods are defined is irrelevant, although
any classes on which they specialize must already exist.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;An unspecialized argument is more or less equivalent to being
specialized on the class &lt;code&gt;t&lt;/code&gt;. The only difference is that
all specialized arguments are implicitly taken to be &amp;ldquo;referred to&amp;rdquo; (in
the sense of &lt;code&gt;declare ignore&lt;/code&gt;.)&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Each &lt;code&gt;defmethod&lt;/code&gt; form generates (and returns) a CLOS
instance, of class &lt;code&gt;standard-method&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;An &lt;code&gt;eql&lt;/code&gt; specializer won&amp;rsquo;t work as is with strings. Indeed, strings
need &lt;code&gt;equal&lt;/code&gt; or &lt;code&gt;equalp&lt;/code&gt; to be compared. But, we can assign our string
to a variable and use the variable both in the &lt;code&gt;eql&lt;/code&gt; specializer and
for the function call.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;All the methods with the same function name belong to the same generic function.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;All slot accessors and readers defined by &lt;code&gt;defclass&lt;/code&gt; are methods. They can override or be overridden by other methods on the same generic function.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See more about &lt;a href=&#34;http://www.lispworks.com/documentation/lw70/CLHS/Body/m_defmet.htm&#34;&gt;defmethod on the CLHS&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;multimethods&#34;&gt;Multimethods&lt;/h2&gt;

&lt;p&gt;Multimethods explicitly specialize more than one of the generic
function&amp;rsquo;s required parameters.&lt;/p&gt;

&lt;p&gt;They don&amp;rsquo;t belong to a particular class. Meaning, we don&amp;rsquo;t have to
decide on the class that would be best to host this method, as we might
have to in other languages.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric hug (a b)
   (:documentation &amp;quot;Hug between two persons.&amp;quot;))
;; #&amp;lt;STANDARD-GENERIC-FUNCTION HUG (0)&amp;gt;

(defmethod hug ((a person) (b person))
  :person-person-hug)

(defmethod hug ((a person) (b child))
  :person-child-hug)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Read more on &lt;a href=&#34;http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html#multimethods&#34;&gt;Practical Common Lisp&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;controlling-setters-setf-ing-methods&#34;&gt;Controlling setters (setf-ing methods)&lt;/h2&gt;

&lt;p&gt;In Lisp, we can define &lt;code&gt;setf&lt;/code&gt; counterparts of functions or methods. We
might want this to have more control on how to update an object.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod (setf name) (new-val (obj person))
  (if (equalp new-val &amp;quot;james bond&amp;quot;)
    (format t &amp;quot;Dude that&#39;s not possible.~&amp;amp;&amp;quot;)
    (setf (slot-value obj &#39;name) new-val)))

(setf (name p1) &amp;quot;james bond&amp;quot;) ;; -&amp;gt; no rename
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you know Python, this behaviour is provided by the &lt;code&gt;@property&lt;/code&gt; decorator.&lt;/p&gt;

&lt;h2 id=&#34;dispatch-mechanism-and-next-methods&#34;&gt;Dispatch mechanism and next methods&lt;/h2&gt;

&lt;p&gt;When a generic function is invoked, the application cannot directly invoke a method. The dispatch mechanism proceeds as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;compute the list of applicable methods&lt;/li&gt;
&lt;li&gt;if no method is applicable then signal an error&lt;/li&gt;
&lt;li&gt;sort the applicable methods in order of specificity&lt;/li&gt;
&lt;li&gt;invoke the most specific method.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our &lt;code&gt;greet&lt;/code&gt; generic function has three applicable methods:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(closer-mop:generic-function-methods #&#39;greet)
(#&amp;lt;STANDARD-METHOD GREET (CHILD) {10098406A3}&amp;gt;
 #&amp;lt;STANDARD-METHOD GREET (PERSON) {1009008EC3}&amp;gt;
 #&amp;lt;STANDARD-METHOD GREET (T) {1008E6EBB3}&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;During the execution of a method, the remaining applicable methods
are still accessible, via the &lt;em&gt;local function&lt;/em&gt;
&lt;code&gt;call-next-method&lt;/code&gt;. This function has lexical scope within
the body of a method but indefinite extent. It invokes the next most
specific method, and returns whatever value that method returned. It
can be called with either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;no arguments, in which case the &lt;em&gt;next method&lt;/em&gt; will
receive exactly the same arguments as this method did, or&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;explicit arguments, in which case it is required that the
sorted set of methods applicable to the new arguments must be the same
as that computed when the generic function was first called.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod greet ((obj child))
  (format t &amp;quot;ur so cute~&amp;amp;&amp;quot;)
  (when (next-method-p)
    (call-next-method)))
;; STYLE-WARNING: REDEFINING GREET (#&amp;lt;STANDARD-CLASS CHILD&amp;gt;) in DEFMETHOD
;; #&amp;lt;STANDARD-METHOD GREET (child) {1003D3DB43}&amp;gt;

(greet c1)
;; ur so cute
;; Hello Alice !
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Calling &lt;code&gt;call-next-method&lt;/code&gt; when there is no next method
signals an error. You can find out whether a next method exists by
calling the local function &lt;code&gt;next-method-p&lt;/code&gt; (which also has
has lexical scope and indefinite extent).&lt;/p&gt;

&lt;p&gt;Note finally that the body of every method establishes a block with the same name as the method’s generic function. If you &lt;code&gt;return-from&lt;/code&gt; that name you are exiting the current method, not the call to the enclosing generic function.&lt;/p&gt;

&lt;h2 id=&#34;method-qualifiers-before-after-around&#34;&gt;Method qualifiers (before, after, around)&lt;/h2&gt;

&lt;p&gt;In our &amp;ldquo;Diving in&amp;rdquo; examples, we saw some use of the &lt;code&gt;:before&lt;/code&gt;, &lt;code&gt;:after&lt;/code&gt; and &lt;code&gt;:around&lt;/code&gt; &lt;em&gt;qualifiers&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(defmethod foo :before (obj) (...))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(defmethod foo :after (obj) (...))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(defmethod foo :around (obj) (...))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, in the &lt;em&gt;standard method combination&lt;/em&gt; framework provided by
CLOS, we can only use one of those three qualifiers, and the flow of control is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;before-method&lt;/strong&gt; is called, well, before the applicable primary
method. If they are many before-methods, &lt;strong&gt;all&lt;/strong&gt; are called. The
most specific before-method is called first (child before person).&lt;/li&gt;
&lt;li&gt;the most specific applicable &lt;strong&gt;primary method&lt;/strong&gt; (a method without
qualifiers) is called (only one).&lt;/li&gt;
&lt;li&gt;all applicable &lt;strong&gt;after-methods&lt;/strong&gt; are called. The most specific one is
called &lt;em&gt;last&lt;/em&gt; (after-method of person, then after-method of child).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The generic function returns the value of the primary method&lt;/strong&gt;. Any
values of the before or after methods are ignored. They are used for
their side effects.&lt;/p&gt;

&lt;p&gt;And then we have &lt;strong&gt;around-methods&lt;/strong&gt;. They are wrappers around the core
mechanism we just described. They can be useful to catch return values
or to set up an environment around the primary method (set up a catch,
a lock, timing an execution,…).&lt;/p&gt;

&lt;p&gt;If the dispatch mechanism finds an around-method, it calls it and
returns its result. If the around-method has a &lt;code&gt;call-next-method&lt;/code&gt;, it
calls the next most applicable around-method. It is only when we reach
the primary method that we start calling the before and after-methods.&lt;/p&gt;

&lt;p&gt;Thus, the full dispatch mechanism for generic functions is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;compute the applicable methods, and partition them into
separate lists according to their qualifier;&lt;/li&gt;
&lt;li&gt;if there is no applicable primary method then signal an
error;&lt;/li&gt;
&lt;li&gt;sort each of the lists into order of specificity;&lt;/li&gt;
&lt;li&gt;execute the most specific &lt;code&gt;:around&lt;/code&gt; method and
return whatever that returns;&lt;/li&gt;
&lt;li&gt;if an &lt;code&gt;:around&lt;/code&gt; method invokes
&lt;code&gt;call-next-method&lt;/code&gt;, execute the next most specific
&lt;code&gt;:around&lt;/code&gt; method;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;if there were no &lt;code&gt;:around&lt;/code&gt; methods in the first
place, or if an &lt;code&gt;:around&lt;/code&gt; method invokes
&lt;code&gt;call-next-method&lt;/code&gt; but there are no further
&lt;code&gt;:around&lt;/code&gt; methods to call, then proceed as follows:&lt;/p&gt;

&lt;p&gt;a.  run all the &lt;code&gt;:before&lt;/code&gt; methods, in order,
        ignoring any return values and not permitting calls to
        &lt;code&gt;call-next-method&lt;/code&gt; or
        &lt;code&gt;next-method-p&lt;/code&gt;;&lt;/p&gt;

&lt;p&gt;b.  execute the most specific primary method and return
        whatever that returns;&lt;/p&gt;

&lt;p&gt;c.  if a primary method invokes &lt;code&gt;call-next-method&lt;/code&gt;,
        execute the next most specific primary method;&lt;/p&gt;

&lt;p&gt;d.  if a primary method invokes &lt;code&gt;call-next-method&lt;/code&gt;
        but there are no further primary methods to call then signal an
        error;&lt;/p&gt;

&lt;p&gt;e.  after the primary method(s) have completed, run all the
        &lt;code&gt;:after&lt;/code&gt; methods, in &lt;strong&gt;&lt;u&gt;reverse&lt;/u&gt;&lt;/strong&gt;
        order, ignoring any return values and not permitting calls to
        &lt;code&gt;call-next-method&lt;/code&gt; or
        &lt;code&gt;next-method-p&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Think of it as an onion, with all the &lt;code&gt;:around&lt;/code&gt;
    methods in the outermost layer, &lt;code&gt;:before&lt;/code&gt; and
    &lt;code&gt;:after&lt;/code&gt; methods in the middle layer, and primary methods
    on the inside.&lt;/p&gt;

&lt;h2 id=&#34;other-method-combinations&#34;&gt;Other method combinations&lt;/h2&gt;

&lt;p&gt;The default method combination type we just saw is named &lt;code&gt;standard&lt;/code&gt;,
but other method combination types are available, and no need to say
that you can define your own.&lt;/p&gt;

&lt;p&gt;The built-in types are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;progn + list nconc and max or append min
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You notice that these types are named after a lisp operator. Indeed,
what they do is they define a framework that combines the applicable
primary methods inside a call to the lisp operator of that name. For
example, using the &lt;code&gt;progn&lt;/code&gt; combination type is equivalent to calling &lt;strong&gt;all&lt;/strong&gt;
the primary methods one after the other:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(progn
  (method-1 args)
  (method-2 args)
  (method-3 args))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, unlike the standard mechanism, all the primary methods
applicable for a given object are called, the most specific
first.&lt;/p&gt;

&lt;p&gt;To change the combination type, we set the &lt;code&gt;:method-combination&lt;/code&gt;
option of &lt;code&gt;defgeneric&lt;/code&gt; and we use it as the methods&amp;rsquo; qualifier:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric foo (obj)
  (:method-combination progn))

(defmethod foo progn ((obj obj))
   (...))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An example with &lt;strong&gt;progn&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric dishes (obj)
   (:method-combination progn)
   (:method progn (obj)
     (format t &amp;quot;- clean and dry.~&amp;amp;&amp;quot;))
   (:method progn ((obj person))
     (format t &amp;quot;- bring a person&#39;s dishes~&amp;amp;&amp;quot;))
   (:method progn ((obj child))
     (format t &amp;quot;- bring the baby dishes~&amp;amp;&amp;quot;)))
;; #&amp;lt;STANDARD-GENERIC-FUNCTION DISHES (3)&amp;gt;

(dishes c1)
;; - bring the baby dishes
;; - bring a person&#39;s dishes
;; - clean and dry.

(greet c1)
;; ur so cute  --&amp;gt; only the most applicable method was called.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Similarly, using the &lt;code&gt;list&lt;/code&gt; type is equivalent to returning the list
of the values of the methods.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(list
  (method-1 args)
  (method-2 args)
  (method-3 args))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric tidy (obj)
  (:method-combination list)
  (:method list (obj)
    :foo)
  (:method list ((obj person))
    :books)
  (:method list ((obj child))
    :toys))
;; #&amp;lt;STANDARD-GENERIC-FUNCTION TIDY (3)&amp;gt;

(tidy c1)
;; (:toys :books :foo)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Around methods&lt;/strong&gt; are accepted:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod tidy :around (obj)
   (let ((res (call-next-method)))
     (format t &amp;quot;I&#39;m going to clean up ~a~&amp;amp;&amp;quot; res)
     (when (&amp;gt; (length res)
              1)
       (format t &amp;quot;that&#39;s too much !~&amp;amp;&amp;quot;))))

(tidy c1)
;; I&#39;m going to clean up (toys book foo)
;; that&#39;s too much !
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that these operators don&amp;rsquo;t support &lt;code&gt;before&lt;/code&gt;, &lt;code&gt;after&lt;/code&gt; and &lt;code&gt;around&lt;/code&gt;
methods (indeed, there is no room for them anymore). They do support
around methods, where &lt;code&gt;call-next-method&lt;/code&gt; is allowed, but they don&amp;rsquo;t
support calling &lt;code&gt;call-next-method&lt;/code&gt; in the primary methods (it would
indeed be redundant since all primary methods are called, or clunky to
&lt;em&gt;not&lt;/em&gt; call one).&lt;/p&gt;

&lt;p&gt;CLOS allows us to define a new operator as a method combination type, be
it a lisp function, macro or special form. We&amp;rsquo;ll let you refer to the
books if you feel the need.&lt;/p&gt;

&lt;h2 id=&#34;debugging-tracing-method-combination&#34;&gt;Debugging: tracing method combination&lt;/h2&gt;

&lt;p&gt;It is possible to &lt;a href=&#34;http://www.xach.com/clhs?q=trace&#34;&gt;trace&lt;/a&gt; the method
combination, but this is implementation dependent.&lt;/p&gt;

&lt;p&gt;In SBCL, we can use &lt;code&gt;(trace foo :methods t)&lt;/code&gt;. See &lt;a href=&#34;http://christophe.rhodes.io/notes/blog/posts/2018/sbcl_method_tracing/&#34;&gt;this post by an SBCL core developer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, given a generic:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric foo (x)
  (:method (x) 3))
(defmethod foo :around ((x fixnum))
  (1+ (call-next-method)))
(defmethod foo ((x integer))
  (* 2 (call-next-method)))
(defmethod foo ((x float))
  (* 3 (call-next-method)))
(defmethod foo :before ((x single-float))
  &#39;single)
(defmethod foo :after ((x double-float))
 &#39;double)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s trace it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(trace foo :methods t)

(foo 2.0d0)
  0: (FOO 2.0d0)
    1: ((SB-PCL::COMBINED-METHOD FOO) 2.0d0)
      2: ((METHOD FOO (FLOAT)) 2.0d0)
        3: ((METHOD FOO (T)) 2.0d0)
        3: (METHOD FOO (T)) returned 3
      2: (METHOD FOO (FLOAT)) returned 9
      2: ((METHOD FOO :AFTER (DOUBLE-FLOAT)) 2.0d0)
      2: (METHOD FOO :AFTER (DOUBLE-FLOAT)) returned DOUBLE
    1: (SB-PCL::COMBINED-METHOD FOO) returned 9
  0: FOO returned 9
9
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&#34;mop&#34;&gt;MOP&lt;/h1&gt;

&lt;p&gt;We gather here some examples that make use of the framework provided
by the meta-object protocol, the configurable object system that rules
Lisp&amp;rsquo;s object system. We touch advanced concepts so, new reader, don&amp;rsquo;t
worry: you don&amp;rsquo;t need to understand this section to start using the
Common Lisp Object System.&lt;/p&gt;

&lt;p&gt;We won&amp;rsquo;t explain much about the MOP here, but hopefully sufficiently
to make you see its possibilities or to help you understand how some
CL libraries are built. We invite you to read the books referenced in
the introduction.&lt;/p&gt;

&lt;h2 id=&#34;metaclasses&#34;&gt;Metaclasses&lt;/h2&gt;

&lt;p&gt;Metaclasses are needed to control the behaviour of other classes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As announced, we won&amp;rsquo;t talk much. See also Wikipedia for &lt;a href=&#34;https://en.wikipedia.org/wiki/Metaclass&#34;&gt;metaclasses&lt;/a&gt; or &lt;a href=&#34;https://en.wikipedia.org/wiki/Common_Lisp_Object_System&#34;&gt;CLOS&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The standard metaclass is &lt;code&gt;standard-class&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(class-of p1) ;; #&amp;lt;STANDARD-CLASS PERSON&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But we&amp;rsquo;ll change it to one of our own, so that we&amp;rsquo;ll be able to
&lt;strong&gt;count the creation of instances&lt;/strong&gt;. This same mechanism could be used
to auto increment the primary key of a database system (this is
how the Postmodern or Mito libraries do), to log the creation of objects,
etc.&lt;/p&gt;

&lt;p&gt;Our metaclass inherits from &lt;code&gt;standard-class&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass counted-class (standard-class)
  ((counter :initform 0)))
#&amp;lt;STANDARD-CLASS COUNTED-CLASS&amp;gt;

(unintern &#39;person)
;; this is necessary to change the metaclass of person.
;; or (setf (find-class &#39;person) nil)
;; https://stackoverflow.com/questions/38811931/how-to-change-classs-metaclass#38812140

(defclass person ()
  ((name
    :initarg :name
    :accessor name)
  (:metaclass counted-class))) ;; &amp;lt;- metaclass
;; #&amp;lt;COUNTED-CLASS PERSON&amp;gt;
;;   ^^^ not standard-class anymore.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;:metaclass&lt;/code&gt; class option can appear only once.&lt;/p&gt;

&lt;p&gt;Actually you should have gotten a message asking to implement
&lt;code&gt;validate-superclass&lt;/code&gt;. So, still with the &lt;code&gt;closer-mop&lt;/code&gt; library:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod closer-mop:validate-superclass ((class counted-class)
                                           (superclass standard-class))
  t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can control the creation of new &lt;code&gt;person&lt;/code&gt; instances:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod make-instance :after ((class counted-class) &amp;amp;key)
  (incf (slot-value class &#39;counter)))
;; #&amp;lt;STANDARD-METHOD MAKE-INSTANCE :AFTER (COUNTED-CLASS) {1007718473}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See that an &lt;code&gt;:after&lt;/code&gt; qualifier is the safest choice, we let the
standard method run as usual and return a new instance.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;amp;key&lt;/code&gt; is necessary, remember that &lt;code&gt;make-instance&lt;/code&gt; is given initargs.&lt;/p&gt;

&lt;p&gt;Now testing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar p3 (make-instance &#39;person :name &amp;quot;adam&amp;quot;))
#&amp;lt;PERSON {1007A8F5B3}&amp;gt;

(slot-value p3 &#39;counter)
;; =&amp;gt; error. No, our new slot isn&#39;t on the person class.
(slot-value (find-class &#39;person) &#39;counter)
;; 1

(make-instance &#39;person :name &amp;quot;eve&amp;quot;)
;; #&amp;lt;PERSON {1007AD5773}&amp;gt;
(slot-value (find-class &#39;person) &#39;counter)
;; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s working.&lt;/p&gt;

&lt;h2 id=&#34;controlling-the-initialization-of-instances-initialize-instance&#34;&gt;Controlling the initialization of instances (initialize-instance)&lt;/h2&gt;

&lt;p&gt;To further customize the creation of instances by specializing
&lt;code&gt;initialize-instance&lt;/code&gt;, which is called by &lt;code&gt;make-instance&lt;/code&gt;, just after
it has created a new instance but didn&amp;rsquo;t initialize it yet with the
default initargs and initforms.&lt;/p&gt;

&lt;p&gt;It is recommended (Keene) to create an after method, since creating a
primary method would prevent slots&amp;rsquo; initialization.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod initialize-instance :after ((obj person) &amp;amp;key)
  (do something with obj))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Another rational. The CLOS implementation of
    &lt;code&gt;make-instance&lt;/code&gt; is in two stages: allocate the new object,
    and then pass it along with all the &lt;code&gt;make-instance&lt;/code&gt; keyword
    arguments, to the generic function
    &lt;code&gt;initialize-instance&lt;/code&gt;. Implementors and application writers
    define &lt;code&gt;:after&lt;/code&gt; methods on
    &lt;code&gt;initialize-instance&lt;/code&gt;, to initialize the slots of the
    instance. The system-supplied primary method does this with regard to
    (a) &lt;code&gt;:initform&lt;/code&gt; and &lt;code&gt;:initarg&lt;/code&gt; values supplied
    with the class was defined and (b) the keywords passed through from
    &lt;code&gt;make-instance&lt;/code&gt;. Other methods can extend this behaviour as
    they see fit. For example, they might accept an additional keyword
    which invokes a database access to fill certain slots. The lambda list
    for &lt;code&gt;initialize-instance&lt;/code&gt; is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;initialize-instance instance &amp;amp;rest initargs &amp;amp;key &amp;amp;allow-other-keys
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See more in the books !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Shuffletron, a Common Lisp Music Player for the terminal</title>
      <link>/blog/shuffletron-lisp-music-player-for-the-terminal/</link>
      <pubDate>Tue, 11 Sep 2018 16:36:23 +0200</pubDate>
      
      <guid>/blog/shuffletron-lisp-music-player-for-the-terminal/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://github.com/ahefner/shuffletron/&#34;&gt;Shuffletron&lt;/a&gt; is a nice music
player for the terminal written in Common Lisp, &amp;ldquo;based on search and
tagging&amp;rdquo;, that seduced me with its attention to details. Moreover, its
author was very responsive to fix a couple issues.&lt;/p&gt;

&lt;p&gt;The first time you launch it, it will ask for a music repository and
will propose to scan it for id3 tags with the &lt;code&gt;scanid3&lt;/code&gt; command. It
is optional, but it allows to print colored information:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://github.com/ahefner/shuffletron/raw/master/img-search.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The basic commands to know are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;search with &lt;code&gt;/&lt;/code&gt; followed by your search terms. You&amp;rsquo;ll notice that
your prompt changed from &lt;code&gt;library&lt;/code&gt; to &lt;code&gt;xy matches&lt;/code&gt;. You can &lt;strong&gt;refine
the results&lt;/strong&gt; by searching again. To enter a new query we have to go
back to the library, with as many successive &amp;ldquo;enters&amp;rdquo; as needed.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;to play songs: &lt;code&gt;play&lt;/code&gt;. We can select which songs to play, using their index:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;comma-separated indexes of songs: &lt;code&gt;1,3,10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a selection with a dash and an optional end: &lt;code&gt;1-10&lt;/code&gt;, &lt;code&gt;0-&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a combination of the two: &lt;code&gt;1,3-10&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;there are the obvious &lt;code&gt;pause&lt;/code&gt;, &lt;code&gt;shuffle&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;seek&lt;/code&gt;, &lt;code&gt;repeat&lt;/code&gt;,…&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;now&lt;/code&gt; to show the currently playing song.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a &lt;strong&gt;queue&lt;/strong&gt;, &lt;strong&gt;id3 tags management&lt;/strong&gt;, &lt;strong&gt;profiles&lt;/strong&gt; to
use an alternate library (&lt;code&gt;./shuffletron --help&lt;/code&gt;), and even an &lt;strong&gt;alarm
clock&lt;/strong&gt; feature which allows to program music with something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  alarm at 7:45 am      # \&amp;quot;at\&amp;quot; is optional and doesn&#39;t change the meaning
  alarm 7:45 am
  alarm 9 pm
  alarm 7               # If AM/PM not specified, assumes AM
  alarm in 5 minutes    # Relative alarm times, in minutes or hours
  alarm in 10m          # minutes, minute, mins, min, , m are synonyms
  alarm in 7 hours      # hours, hour, hr, h are synonyms
  alarm in 8h
  alarm in 7:29         # h:mm format - seven hours, twenty-nine minutes
  alarm reset           # off/never/delete/disable/cancel/clear/reset
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I can see a use for a pomodoro-like technic :)&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll list the complete set of commands below (available
&lt;a href=&#34;https://github.com/ahefner/shuffletron/blob/master/src/help.lisp&#34;&gt;on the sources&lt;/a&gt;),
but first a note on installation.&lt;/p&gt;

&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Shuffletron doesn&amp;rsquo;t provide executables
(&lt;a href=&#34;https://github.com/ahefner/shuffletron/issues/6&#34;&gt;yet ?&lt;/a&gt;). The
procedure is now documented in the readme so you just have to&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;make shuffletron-bin  # sbcl
sudo make install
./shuffletron
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This last line calls a script and it is actually important to use it,
to link dependencies and to use &lt;code&gt;rlwrap&lt;/code&gt;. There is room for
improvement here.&lt;/p&gt;

&lt;p&gt;To read Flac and Ogg files, you need those system dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apt install libflac-dev
apt install libvorbis-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, scanning my library failed for the first time, because of
badly manually encoded ogg files coming from youtube. The mixalot
library prefered to fail instead of showing error messages. If you
encounter a similar problem, see
&lt;a href=&#34;https://github.com/ahefner/mixalot/pull/7&#34;&gt;this PR&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;all-commands&#34;&gt;All commands&lt;/h2&gt;

&lt;p&gt;In the application, type &lt;code&gt;help&lt;/code&gt;, and &lt;code&gt;help commands&lt;/code&gt; to get this list:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Command list:

  /[query]       Search library for [query].
  show           Print search matches, highlighting songs in queue.
  back           Undo last search.
  [songs]        Play list of songs.
  all            Play all songs in selection (equivalent to \&amp;quot;0-\&amp;quot;)
  +[songs]       Append list of songs to queue.
  pre[songs]     Prepend list of songs to queue.
  random         Play a random song from the current selection.
  random QUERY   Play a random song matching QUERY
  shuffle SONGS  Play songs in random order.

  queue          Print queue contents and current song playing.
  shuffle        Randomize order of songs in queue.
  clear          Clear the queue (current song continues playing)
  loop           Toggle loop mode (loop through songs in queue)
  qdrop          Remove last song from queue
  qdrop RANGES   Remove songs from queue
  qtag TAGS      Apply tags to all songs in queue
  fromqueue      Transfer queue to selection
  toqueue        Replace queue with selection

  now            Print name of song currently playing.
  play           Resume playing
  stop           Stop playing (current song pushed to head of queue)
  pause          Toggle paused/unpaused.
  skip           Skip currently playing song. If looping is enabled, this
                 song won&#39;t played again.
  next           Advance to next song. If looping is enabled, the current
                 song will be enqueued.
  repeat N       Add N repetitions of currently playing song to head of queue.
  seek TIME      Seek to time (in [h:]m:ss format, or a number in seconds)
  seek +TIME     Seek forward
  seek -TIME     Seek backward
  startat TIME   Always start playback at a given time (to skip long intros)

  tag            List tags of currently playing song.
  tag TAGS       Add one or more textual tags to the current song.
  untag TAGS     Remove the given tags from the currently playing song.
  tagged TAGS    Search for files having any of specified tags.
  tags           List all tags (and # occurrences) within current query.
  killtag TAGS   Remove all occurances of the given tags
  tagall TAGS    Apply tags to all selected songs
  untagall TAGS  Remove given tags from all selected songs

  time           Print current time
  alarm          Set alarm (see \&amp;quot;help alarms\&amp;quot;)

  scanid3        Scan new files for ID3 tags
  prescan        Toggle file prescanning (useful if file IO is slow)
  exit           Exit the program.

  help [topic]   Help
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/stassats/mpd&#34;&gt;mpd&lt;/a&gt;, an interface to Music Player
Daemon in CL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;other music players:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cmus.github.io/&#34;&gt;cmus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Emacs&amp;rsquo; media players &lt;a href=&#34;http://wikemacs.org/wiki/Media_player&#34;&gt;http://wikemacs.org/wiki/Media_player&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>These Months in Common Lisp: Q2 2018</title>
      <link>/blog/these-months-in-common-lisp-q2-2018/</link>
      <pubDate>Mon, 02 Jul 2018 14:59:46 +0200</pubDate>
      
      <guid>/blog/these-months-in-common-lisp-q2-2018/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q1-2018/&#34;&gt;Q1 2018&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/norvig/paip-lisp/blob/master/PAIP-safari.epub&#34;&gt;Paradigms of Artificial Intelligence Programming epub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;Models and Databases, with Mito and SxQL - the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/GustavBertram/awesome-common-lisp-learning-list&#34;&gt;Awesome Common Lisp learning list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;announcements&#34;&gt;Announcements&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.european-lisp-symposium.org/static/proceedings/2018.pdf&#34;&gt;ELS2018 proceedings (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://sbcl.org/all-news.html?1.4.6#1.4.6&#34;&gt;SBCL 1.4.6 released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://sbcl.org/all-news.html?1.4.7&#34;&gt;SBCL 1.4.7 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/downloads/patch-selection.html&#34;&gt;LispWorks 7.1.1 - Patches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://christophe.rhodes.io/notes/blog/posts/2018/sbcl_method-combination_fixes/&#34;&gt;SBCL method-combination fixes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://christophe.rhodes.io/notes/blog/posts/2018/sbcl_method_tracing/&#34;&gt;SBCL method tracing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.bountysource.com/issues/47099106-use-microsoft-tools-to-build-lisp-kernel&#34;&gt;$500 Bounty on Clozure/ccl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;jobs&#34;&gt;Jobs&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lispjobs.wordpress.com/2018/04/16/junior-lisp-developer-ravenpack-marbella-spain/&#34;&gt;Junior Lisp Developer, RavenPack, Marbella, Spain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://3eeu.talentfinder.be/en/vacature/30101/lisp-developer&#34;&gt;3E : Lisp Developer - development, maintenance, design and unit testing of SynaptiQ’s real-time aggregation and alerting engine that processes time-series and events. This data engine is Common Lisp based.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.indeed.com/viewjob?t=lisp+engineer+ai+natural+language+reasoning&amp;amp;jk=d14c7726839e6b01&amp;amp;_ga=2.203861651.2000107742.1525918694-1699101565.1509521844&#34;&gt;Lisp Engineer - AI (Natural Language Reasoning)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;p&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/03/quicklisp-dist-update-for-march-2018.html&#34;&gt;Quicklisp dist update, march 2018&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bradleyjensen/shcl&#34;&gt;SHCL: An Unholy Union of POSIX Shell and Common Lisp&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8kpbcz/shcl_an_unholy_union_of_posix_shell_and_common/&#34;&gt;reddit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/inaimathi/cl-notebook/&#34;&gt;cl-notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp&#34;&gt;Heroku buildpack for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/xh4/cube&#34;&gt;Kubernetes Client Library for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.klipse.tech/lisp/2018/05/07/blog-common-lisp.html&#34;&gt;Interactive Common Lisp code snippets in any web page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/rove/&#34;&gt;rove&lt;/a&gt; - small testing framework (Fukamachi&amp;rsquo;s successor to Prove)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/03/quicklisp-dist-update-for-march-2018.html&#34;&gt;can&lt;/a&gt; - a role-based access right control library&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/inaimathi/house/&#34;&gt;house&lt;/a&gt; - custom asynchronous HTTP server for the Deal project.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shinmera/oxenfurt&#34;&gt;oxenfurt&lt;/a&gt; - A Common Lisp client library for the Oxford dictionary API.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/tarballs-are-good/algebraic-data-library/&#34;&gt;algebraic-data-library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plkrueger/CommonLispFred&#34;&gt;Lisp Interface to Federal Reserve Economic Data (FRED®)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reddit-archive/reddit1.0&#34;&gt;reddit1.0 source code&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/886yeu/reddit10/&#34;&gt;comments&lt;/a&gt;), then &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8ata3c/reddit_code_runs_on_sbcl/&#34;&gt;Reddit&amp;rsquo;s code runs on SBCL&lt;/a&gt;. See also &lt;a href=&#34;https://www.reddit.com/r/programming/comments/883vzs/old_reddit_source_code/&#34;&gt;reddit&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8f6wez/petalisp_elegant_high_performance_computing/&#34;&gt;Petalisp&lt;/a&gt;: Elegant High Performance Computing&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://code-golf.io/&#34;&gt;Code Golf Site with Common Lisp Support!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vseloved/wiki-lang-detect&#34;&gt;vseloved/wiki-lang-detect&lt;/a&gt;: Text language identification using Wikipedia data&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8gzm4w/ppath_a_path_manipulation_library/&#34;&gt;ppath, a path manipulation library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://cram-system.org/&#34;&gt;CRAM&lt;/a&gt;: Cognitive Robot Abstract Machine - a toolbox for designing, implementing and deploying software on autonomous robots&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://compbio.ucdenver.edu/Hunter_lab/Hunter/cl-statistics.lisp&#34;&gt;cl-statistics.lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://mumble.net/~jar/pseudoscheme/&#34;&gt;Pseudoscheme - An implementation of Scheme embedded in Common Lisp&lt;/a&gt; (&amp;ldquo;with minor changes it runs in ABCL, CCL, ECL and LispWorks. But not in SBCL&amp;hellip;&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/luksamuk/powerlisp&#34;&gt;Powerlisp: A simple tool to automate your work with dmenu/rofi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://eschulte.github.io/curry-compose-reader-macros/&#34;&gt;curry-compose-reader-macros&lt;/a&gt; - concise function partial application and composition&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gschjetne/json-mop&#34;&gt;json-mop&lt;/a&gt;: A metaclass for bridging CLOS and JSON objects&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/obicons/clsh&#34;&gt;clsh&lt;/a&gt;: a set of Lispy bindings for running and composing *nix processes&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/BnMcGn/snakes&#34;&gt;snakes&lt;/a&gt; - Python style generators for Common Lisp. (Includes a port of itertools.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;new releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/portacle/portacle/releases/tag/1.2&#34;&gt;Portacle: Release Linux Portability Fixes, Included SLY, Usability Improvements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(re)discoveries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plkrueger/CocoaInterface&#34;&gt;Cocoa interface code written in Lisp for use with Clozure Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/882mz4/clbench_common_lisp_benchmarking_suite/&#34;&gt;cl-bench - Common Lisp benchmarking suite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/88xin6/eclipse_common_lisp_howard_stearns_elwood_corp/&#34;&gt;Eclipse Common Lisp (Howard Stearns / Elwood Corp)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Arboreta/arboreta-wasm/blob/master/wasm.cl&#34;&gt;Arboreta/arboreta-wasm - Common Lisp tooling for WebAssembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://faculty.hampshire.edu/lspector/qgame.html&#34;&gt;QGAME: Quantum and Gate Measurement Emulator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/guicho271828/trivia&#34;&gt;Trivia: Pattern Matching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the Lisp Game Jam 2018:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://pages.cs.wisc.edu/~psilord/lisp-public/option-9.html&#34;&gt;Option 9: A Shoot&amp;rsquo;em Up Miniature Video Game in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://luksamuk.itch.io/cl-ods&#34;&gt;Orbit Defense Strikeforce&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;all &lt;a href=&#34;https://www.indeed.com/viewjob?t=lisp+engineer+ai+natural+language+reasoning&amp;amp;jk=d14c7726839e6b01&amp;amp;_ga=2.203861651.2000107742.1525918694-1699101565.1509521844&#34;&gt;results&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&#34;articles&#34;&gt;Articles&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8bshzw/lisp_jazz_aikido_three_expressions_of_a_single/&#34;&gt;Lisp, Jazz, Aikido: Three Expressions of a Single Essence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://funlisp.blogspot.com/2018/03/creating-cl-rivescript-interpreter-part.html&#34;&gt;Creating a CL-Rivescript Interpreter (Part 1)&lt;/a&gt; and &lt;a href=&#34;http://funlisp.blogspot.com/2018/04/creating-cl-rivescript-interpreter-part_14.html&#34;&gt;part 10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://biolisp.github.io/#why-lisp&#34;&gt;Why lisp - biolisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ebzzry.io/en/script-lisp/&#34;&gt;Scripting in Common Lisp with buildapp&amp;rsquo;s multi-call binaries and fare&amp;rsquo;s cl-scripting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/05/fun-with-macros-gathering/&#34;&gt;Fun with Macros: Gathering / Steve Losh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.rangakrish.com/index.php/2018/05/27/calling-go-functions-from-lisp/&#34;&gt;Calling Go Functions from Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispology.com/show?27LP&#34;&gt;Lispology - Printing floating-point numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8pa6rg/prolog_to_lisp/&#34;&gt;Prolog to Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8svch2/how_do_you_design_with_prolog_in_lisp/&#34;&gt;How do you design with Prolog in Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8qca4o/when_to_use_type_specifiers_in_cl_code/&#34;&gt;When to use type specifiers in CL code?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://codeninja.blog/2018/lisp-code/&#34;&gt;Jeff Massung: Common Lisp libraries that I made over the course of a few years and have consistenly returned to, always found useful, and kept up-to-date.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://can3p.github.io/blog/2018/06/19/client-writeup-intro/&#34;&gt;Experience writing a full featured livejournal blog client in Common Lisp&lt;/a&gt;. Part 2: &lt;a href=&#34;http://can3p.github.io/blog/2018/06/22/client-writeup-logic/&#34;&gt;client logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lthms.xyz/blog/lisp-journey-getting-started&#34;&gt;My Lisp Journey #1: Getting Started With trivial-gamekit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8o2c1y/the_uncommon_lisp_approach_to_operations_research/&#34;&gt;The (Un)common Lisp approach to Operations Research (2012)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8jq465/alien_return_of_alien_technology_to_classical/&#34;&gt;Alien: Return of Alien Technology to Classical Planning &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;discussion&#34;&gt;Discussion&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8s5q7x/what_common_lisp_web_library_should_i_use/&#34;&gt;What Common Lisp web library should I use?&lt;/a&gt;, and &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8k79iz/lisp_for_building_a_web_app_options/&#34;&gt;Lisp for building a web app, options?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/82wiyt/how_to_collect_all_asdf_dependencies_for/&#34;&gt;How to collect all asdf dependencies for package-inferred-system?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/85oo81/sbcl_on_raspberry_pi/&#34;&gt;SBCL on Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8665ga/please_join_the_cltelegrambot_refactoring_effort/&#34;&gt;Please, join the cl-telegram-bot refactoring effort!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/1jq5rk/common_lisp_gui_options/cbhh1y2/&#34;&gt;GUI development done in Lisp (2013 comment)&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/86mbhc/gui_development_done_in_lisp_2013_comment/&#34;&gt;reddit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8ald5m/question_trying_to_generalize_posix_stat_functions/&#34;&gt;Question: trying to generalize posix &amp;lsquo;stat-&amp;rsquo; functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8azd8n/package_name_and_nickname_collisions_in_quicklisp/&#34;&gt;Package Name and Nickname Collisions in Quicklisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8bn7f9/common_lisp_and_machine_learning_these_days/&#34;&gt;Common Lisp and Machine Learning these days&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8bqava/is_clautowrap_the_preferred_way_to_generate_ffi/&#34;&gt;Is cl-autowrap the preferred way to generate FFI bindings these days?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8oy69a/want_to_make_it_so_common_lisp_understands/&#34;&gt;Want to make it so Common Lisp understands GeoJSON data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8szurv/how_to_send_and_receive_data_over_udp/&#34;&gt;How to send and receive data over UDP asynchronously in common lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stevelosh.com/blog/2018/05/fun-with-macros-gathering/&#34;&gt;Fun with Macros: Gathering / Steve Losh &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning Lisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8r9jfc/one_package_per_or_file_project_somethingelse/&#34;&gt;One package per (or file project something-else)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8nt95a/small_executables_in_lisp/&#34;&gt;Small executables in LISP ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8sgqfq/what_can_sly_do_outofthemetaphoricalbox_that/&#34;&gt;What can Sly do out-of-the-metaphorical-box that slime+slime-company+&lt;some-other-contribs&gt; can&amp;rsquo;t?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8a8sps/til_that_i_can_create_clos_constructors_for/&#34;&gt;TIL that I can create CLOS constructors for conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8cwemh/macro_question_from_a_clojure_programmer/&#34;&gt;Macro question from a Clojure programmer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8jzpzw/why_did_you_decide_to_learn_lisp/&#34;&gt;Why did you decide to learn Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8j9ing/how_do_you_go_about_starting_a_common_lisp/&#34;&gt;How do you go about starting a Common Lisp Project? A beginner looking for pointers.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;screencasts&#34;&gt;Screencasts&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/A5CnYlG7sc8&#34;&gt;Lots of bits of lisp - CFFI &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=ygKXeLKhiTI&#34;&gt;Lots of bits of Lisp - Macros (2 hr episode) &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=2Op3QLzMgSY&amp;amp;t=106s&#34;&gt;MIT OpenCourseWare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=dw-y3vNDRWk&#34;&gt;Lisp, The Quantum Programmer&amp;rsquo;s Choice - Computerphile episode 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=9VIT_Ml2v-Q&#34;&gt;McCLIM + Maxima: plot manipulation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=AvC82EjoPYU&#34;&gt;McCLIM + Maxima: vector demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=CbfHpLUPL7E&#34;&gt;Comfy Lisp Programming - Project &amp;ldquo;Wikify&amp;rdquo; | Episode 2 @ 10am PST &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/Zv_0U5kVIf8&#34;&gt;Pushing Pixels with Lisp - Episode 45 - World space shenanigans &amp;amp; Vignette&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8ubnkn/common_lisp_and_c17_live_coding_stream_tinycdn/&#34;&gt;Common lisp and C++17 Live coding stream | TinyCDN CFFI Interop | Episode 13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=XT7JYPtWMd8&#34;&gt;Growing a Lisp compiler - Amsterdam Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=bl8jQ2wRh6k&#34;&gt;Web Development in Emacs, Common Lisp and Clojurescript - Potato (Slack-like)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8rsnec/any_news_on_the_els_videos/&#34;&gt;Any news on the ELS videos?&lt;/a&gt; (answer: no)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;common-lisp-vs&#34;&gt;Common Lisp VS &amp;hellip;&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://med.miami.edu/news/miller-school-researchers-help-push-the-limits-of-programming-languages-in-&#34;&gt;Miller School Researchers Help Push the Limits of Programming Languages in Biology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8mcts3/lisp_vs_java_thought_you_guys_might_find_this/&#34;&gt;Lisp vs Java (thought you guys might find this humorous)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8q6gaa/what_other_languages_besides_lisp_do_you_enjoy/&#34;&gt;What other languages besides Lisp do you enjoy programming in?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>New Weblocks tutorial: widgets</title>
      <link>/blog/new-weblocks-tutorial/</link>
      <pubDate>Mon, 25 Jun 2018 18:51:49 +0100</pubDate>
      
      <guid>/blog/new-weblocks-tutorial/</guid>
      <description>

&lt;p&gt;Weblocks is a web framework, created circa 2007, that allows to
&lt;strong&gt;write dynamic web applications in full Lisp, without a line of
Javascript&lt;/strong&gt;. It is based on so called widgets, that are rendered
server-side and updated on the client, and it was also based on
continuations (they were removed in this fork, at least for now). It
was quietly being forgotten but it is being fixed, refactored,
documented and simplified by Alexander &amp;ldquo;svetlyak40wt&amp;rdquo; since a year or
so.&lt;/p&gt;

&lt;p&gt;I rewrote the quickstart to show the use of widgets, the heart of
Weblocks, Alexander proof-read and here we are:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://40ants.com/weblocks/quickstart.html&#34;&gt;http://40ants.com/weblocks/quickstart.html&lt;/a&gt; (and &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/8tpkge/new_weblocks_web_framework_quickstart_widgets/&#34;&gt;reddit comments&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I copy it below, of course check the official website for updates.&lt;/p&gt;

&lt;p&gt;The old Weblocks website is at &lt;a href=&#34;https://common-lisp.net/project/cl-weblocks/&#34;&gt;https://common-lisp.net/project/cl-weblocks/&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Btw, other isomorphic web frameworks I know are Haskell&amp;rsquo;s
&lt;a href=&#34;https://haste-lang.org/docs/&#34;&gt;Haste&lt;/a&gt;, Nim&amp;rsquo;s
&lt;a href=&#34;https://github.com/pragmagic/karax&#34;&gt;Karax&lt;/a&gt;, Ocaml&amp;rsquo;s
&lt;a href=&#34;http://ocsigen.org/eliom/&#34;&gt;Heliom&lt;/a&gt;, Python&amp;rsquo;s
&lt;a href=&#34;http://www.nagare.org/&#34;&gt;Nagare&lt;/a&gt;, of course Smalltalk&amp;rsquo;s
&lt;a href=&#34;http://seaside.st/&#34;&gt;Seaside&lt;/a&gt; and
&lt;a href=&#34;https://github.com/vindarel/awesome-no-js-web-frameworks&#34;&gt;a couple more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Weblocks is now the easiest to get started with, the one &amp;ldquo;really
isomorphic&amp;rdquo; (bluring the line between server and client code), the
most elegant (to me) and one of the two, with Seaside, that allow for
REPL-driven development.&lt;/p&gt;

&lt;p&gt;For what I tested, Heliom is a hell to install, it seems a hell to
deploy, and it is bloated with specific Ocaml syntax that is always
upcoming in new compiler versions.&lt;/p&gt;

&lt;p&gt;Karax seems promising, it was recently used to rewrite the
&lt;a href=&#34;https://forum.nim-lang.org/&#34;&gt;Nim forum&lt;/a&gt;. It has currently zero docs
(not even a quickstart ;) ) and Nim&amp;rsquo;s ecosystem isn&amp;rsquo;t near as large as
CL&amp;rsquo;s. (and, well, no REPL, no Lisp)&lt;/p&gt;

&lt;p&gt;Nagare is actually based on Stackless Python. Looking at the code of
the successfull &lt;a href=&#34;http://www.kansha.org/&#34;&gt;Kansha&lt;/a&gt; Trello clone, it
actually includes inline Javascript. And personnally, I&amp;rsquo;m running away from Python so…&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&#34;quickstart&#34;&gt;Quickstart&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;warning&lt;/strong&gt;&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;This version of Weblocks is not in Quicklisp yet. To&lt;/dt&gt;
&lt;dd&gt;install it you need to clone the repository somewhere where ASDF
will find it, for example, to the &lt;code&gt;~/common-lisp/&lt;/code&gt; directory.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;Load weblocks and create a package for a sandbox:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;CL-USER&amp;gt; (ql:quickload &#39;(:weblocks :weblocks-ui :find-port))
CL-USER&amp;gt; (defpackage todo
           (:use #:cl
                 #:weblocks-ui/form
                 #:weblocks/html)
           (:import-from #:weblocks/widget
                    #:render
                    #:update
                    #:defwidget)
           (:import-from #:weblocks/actions
                    #:make-js-action)
           (:import-from #:weblocks/app
                    #:defapp))
#&amp;lt;PACKAGE &amp;quot;TODO&amp;quot;&amp;gt;
CL-USER&amp;gt; (in-package todo)
#&amp;lt;PACKAGE &amp;quot;TODO&amp;quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, create an application:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defapp tasks)
TODO&amp;gt; (weblocks/debug:on)
TODO&amp;gt; (defvar *port* (find-port:find-port))
TODO&amp;gt; (weblocks/server:start :port *port*)
 &amp;lt;INFO&amp;gt; [19:41:00] weblocks/server server.lisp (start) -
  Starting weblocks WEBLOCKS/SERVER::PORT: 40000
  WEBLOCKS/SERVER::SERVER-TYPE: :HUNCHENTOOT DEBUG: T
 &amp;lt;INFO&amp;gt; [19:41:00] weblocks/server server.lisp (start-server) -
  Starting webserver on WEBLOCKS/SERVER::INTERFACE: &amp;quot;localhost&amp;quot;
  WEBLOCKS/SERVER::PORT: 40000 DEBUG: T
 #&amp;lt;SERVER port=40000 running&amp;gt;
 (NIL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Open &lt;a href=&#34;http://localhost:40000/tasks/&#34;&gt;http://localhost:40000/tasks/&lt;/a&gt; in your browser (double check the
port) and you&amp;rsquo;ll see a text like that:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;No weblocks/session:init method defined.
Please define a method weblocks.session:init to initialize a session.

It could be something simple, like this one:

(defmethod weblocks/session:init ((app tasks))
            &amp;quot;Hello world!&amp;quot;)

Read more in the documentaion.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It means that you didn&amp;rsquo;t write any code for your application. Let&amp;rsquo;s do
it now and make an application which outputs a list of tasks.&lt;/p&gt;

&lt;p&gt;In the end, we&amp;rsquo;ll build the mandatory TODO-list app:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;http://40ants.com/weblocks/_images/quickstart-check-task.gif&#34; alt=&#34;the TODO-list app in Weblocks.&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;the-task-widget&#34;&gt;The Task widget&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defwidget task ()
        ((title
          :initarg :title
          :accessor title)
         (done
          :initarg :done
          :initform nil
          :accessor done)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code defines a task widget, the building block of our application.
&lt;code&gt;defwidget&lt;/code&gt; is similar to Common Lisp&amp;rsquo;s &lt;code&gt;defclass&lt;/code&gt;, in fact it is only a
wrapper around it. It takes a name, a list of super-classes (here &lt;code&gt;()&lt;/code&gt;)
and a list of slot definitions.&lt;/p&gt;

&lt;p&gt;We can create a task with &lt;code&gt;make-instance&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defvar *task-1* (make-instance &#39;task :title &amp;quot;Make my first Weblocks app&amp;quot;))
TODO&amp;gt; *task-1*
#&amp;lt;TASK {1005406F33}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Above, &lt;code&gt;:title&lt;/code&gt; is the initarg, and since we didn&amp;rsquo;t give a &lt;code&gt;:done&lt;/code&gt;
argument, it will be instanciated to its &lt;code&gt;:initform&lt;/code&gt;, which is &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We defined accessors for both slots, so we can read and set them easily:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (title *task-1*)
&amp;quot;Make my first Weblocks app&amp;quot;
TODO&amp;gt; (done *TASK-1*)
NIL
TODO&amp;gt; (setf (done *TASK-1*) t)
T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We define a constructor for our task:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defun make-task (&amp;amp;key title done)
        (make-instance &#39;task :title title :done done))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It isn&amp;rsquo;t mandatory, but it is good practice to do so.&lt;/p&gt;

&lt;p&gt;If you are not familiar with the Common Lisp Object System (CLOS), you
can have a look at &lt;a href=&#34;http://www.gigamonkeys.com/book/object-reorientation-classes.html&#34;&gt;Practical Common
Lisp&lt;/a&gt;
and the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;Common Lisp
Cookbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s carry on with our application.&lt;/p&gt;

&lt;h2 id=&#34;the-tasks-list-widget&#34;&gt;The Tasks-list widget&lt;/h2&gt;

&lt;p&gt;Below we define a more general widget that contains a list of tasks, and
we tell Weblocks how to display them by &lt;em&gt;specializing&lt;/em&gt; the &lt;code&gt;render&lt;/code&gt;
method for our newly defined classes:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defwidget task-list ()
        ((tasks
          :initarg :tasks
          :accessor tasks)))

TODO&amp;gt; (defmethod render ((task task))
        &amp;quot;Render a task.&amp;quot;
        (with-html
              (:span (if (done task)
                         (with-html
                               (:s (title task)))
                       (title task)))))

TODO&amp;gt; (defmethod render ((widget task-list))
        &amp;quot;Render a list of tasks.&amp;quot;
        (with-html
              (:h1 &amp;quot;Tasks&amp;quot;)
              (:ul
                (loop for task in (tasks widget) do
                      (:li (render task))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;with-html&lt;/code&gt; macro uses
&lt;a href=&#34;https://github.com/ruricolist/spinneret/&#34;&gt;Spinneret&lt;/a&gt; under the hood,
but you can use anything that outputs html.&lt;/p&gt;

&lt;p&gt;We can check how the generated html looks like by calling &lt;code&gt;render&lt;/code&gt; in
the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (render *task-1*)
&amp;lt;div class=&amp;quot;widget task&amp;quot;&amp;gt;&amp;lt;span&amp;gt;Make my first Weblocks app&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But we still don&amp;rsquo;t get anything in the browser.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defun make-task-list (&amp;amp;rest rest)
             &amp;quot;Create some tasks from titles.&amp;quot;
             (loop for title in rest collect
                   (make-task :title title)))

TODO&amp;gt; (defmethod weblocks/session:init ((app tasks))
         (declare (ignorable app))
         (let ((tasks (make-task-list &amp;quot;Make my first Weblocks app&amp;quot;
                                      &amp;quot;Deploy it somewhere&amp;quot;
                                      &amp;quot;Have a profit&amp;quot;)))
           (make-instance &#39;task-list :tasks tasks)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This defines a list of tasks (for simplicity, they are defined as a list
in memory) and returns what will be our session&amp;rsquo;s root widget..&lt;/p&gt;

&lt;p&gt;Restart the application:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (weblocks/debug:reset-latest-session)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Right now it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;_static/quickstart-list.png&#34; alt=&#34;Our first list of tasks.&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;adding-tasks&#34;&gt;Adding tasks&lt;/h2&gt;

&lt;p&gt;Now, we&amp;rsquo;ll add some ability to interact with a list – to add some tasks
into it, like so:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;_static/quickstart-add-task.gif&#34; alt=&#34;Adding tasks in our TODO-list interactively.&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Import a new module, &lt;code&gt;weblocks-ui&lt;/code&gt; to help in creating forms and other
UI elements:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (ql:quickload &amp;quot;weblocks-ui&amp;quot;)
TODO&amp;gt; (use-package :weblocks-ui/form)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Write a new &lt;code&gt;add-task&lt;/code&gt; function and modify the &lt;code&gt;render&lt;/code&gt; method of a
task-list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defmethod render ((widget task-list))
          (flet ((add-task (&amp;amp;key title &amp;amp;allow-other-keys)
                   (push (make-task :title title)
                         (tasks (weblocks/widgets/root:get)))
                   (update (weblocks/widgets/root:get))))
            (with-html
              (:h1 &amp;quot;Tasks&amp;quot;)
              (loop for task in (tasks widget) do
                   (render task))
              (with-html-form (:POST #&#39;add-task)
                (:input :type &amp;quot;text&amp;quot;
                        :name &amp;quot;title&amp;quot;
                        :placeholder &amp;quot;Task&#39;s title&amp;quot;)
                (:input :type &amp;quot;submit&amp;quot;
                        :value &amp;quot;Add&amp;quot;)))))

TODO&amp;gt; (weblocks/debug:reset-latest-session)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The function &lt;code&gt;add-task&lt;/code&gt; does only two simple things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it adds a task into a list;&lt;/li&gt;
&lt;li&gt;it tells Weblocks that our root widget should be redrawn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This second point is really important because it allows Weblocks to
render necessary parts of the page on the server and to inject it into
the HTML DOM in the browser. Here it rerenders the root widget, but we
can as well &lt;code&gt;update&lt;/code&gt; a specific task widget, as we&amp;rsquo;ll do soon.&lt;/p&gt;

&lt;p&gt;We also took care of defining &lt;code&gt;add-task&lt;/code&gt; inline, as a closure, for it to
be thread safe.&lt;/p&gt;

&lt;p&gt;Another block in our new version of &lt;code&gt;render&lt;/code&gt; of a task-list is the form:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp&#34;&gt;(with-html-form (:POST #&#39;add-task)
   (:input :type &amp;quot;text&amp;quot;
    :name &amp;quot;task&amp;quot;
    :placeholder &amp;quot;Task&#39;s title&amp;quot;)
   (:input :type &amp;quot;submit&amp;quot;
    :value &amp;quot;Add&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It defines a text field, a submit button and an action to perform on
form submit. The &lt;code&gt;add-task&lt;/code&gt; function will receive the text input as
argument.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is really amazing!&lt;/p&gt;

&lt;p&gt;With Weblocks, you can handle all the business logic server-side,
because an action can be any lisp function, even an anonymous lambda,
closuring all necessary variables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Restart the application and reload the page. Test your form now and see
in a
&lt;a href=&#34;https://developers.google.com/web/tools/chrome-devtools/inspect-styles/&#34;&gt;Webinspector&lt;/a&gt;
how Weblocks sends requests to the server and receives HTML code with
rendered HTML block.&lt;/p&gt;

&lt;p&gt;Now we&amp;rsquo;ll make our application really useful – we&amp;rsquo;ll add code to toggle
the tasks&amp;rsquo; status.&lt;/p&gt;

&lt;h2 id=&#34;toggle-tasks&#34;&gt;Toggle tasks&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-sourceCode common-lisp-repl&#34;&gt;TODO&amp;gt; (defmethod toggle ((task task))
        (setf (done task)
              (if (done task)
                  nil
                  t))
        (update task))

TODO&amp;gt; (defmethod render ((task task))
        (with-html
          (:p (:input :type &amp;quot;checkbox&amp;quot;
            :checked (done task)
            :onclick (make-js-action
                      (lambda (&amp;amp;rest rest)
                        (declare (ignore rest))
                      (toggle task))))
              (:span (if (done task)
                   (with-html
                         ;; strike
                         (:s (title task)))
                 (title task))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We defined a small helper to toggle the &lt;code&gt;done&lt;/code&gt; attribute, and we&amp;rsquo;ve
modified our task rendering function by adding a code to render a
checkbox with an anonymous lisp function, attached to its &lt;code&gt;onclick&lt;/code&gt;
attribute.&lt;/p&gt;

&lt;p&gt;The function &lt;code&gt;make-js-action&lt;/code&gt; returns a Javascript code, which calls
back a lisp lambda function when evaluated in the browser. And because
&lt;code&gt;toggle&lt;/code&gt; updates a Task widget, Weblocks returns on this callback a new
prerendered HTML for this one task only.&lt;/p&gt;

&lt;h2 id=&#34;what-is-next&#34;&gt;What is next?&lt;/h2&gt;

&lt;p&gt;As a homework:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Play with lambdas and add a &amp;ldquo;Delete&amp;rdquo; button next after each task.&lt;/li&gt;
&lt;li&gt;Add the ability to sort tasks by name or by completion flag.&lt;/li&gt;
&lt;li&gt;Save tasks in a database (the
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;Cookbook&lt;/a&gt;
might help).&lt;/li&gt;
&lt;li&gt;Read the rest of the documentation and make a real application,
using the full power of Common Lisp.&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Models and databases with the Mito ORM and SxQL</title>
      <link>/blog/models-and-databases-mito-sxql/</link>
      <pubDate>Tue, 29 May 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/models-and-databases-mito-sxql/</guid>
      <description>

&lt;p&gt;Following is a tutorial on how to use the Mito ORM.&lt;/p&gt;

&lt;p&gt;As usual, this is best read on the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/databases.html&#34;&gt;Common Lisp Cookbook&lt;/a&gt;. It will be updated there.&lt;/p&gt;

&lt;p&gt;The
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#database&#34;&gt;Database section on the Awesome-cl list&lt;/a&gt;
is a resource listing popular libraries to work with different kind of
databases. We can group them roughly in four categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wrappers to one database engine (cl-sqlite, postmodern, cl-redis,…),&lt;/li&gt;
&lt;li&gt;interfaces to several DB engines (clsql, sxql,…),&lt;/li&gt;
&lt;li&gt;persistent object databases (bknr.datastore (see chap. 21 of &amp;ldquo;Common Lisp Recipes&amp;rdquo;), ubiquitous,…),&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Object-relational_mapping&#34;&gt;Object Relational Mappers&lt;/a&gt; (Mito),&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and other DB-related tools (pgloader).&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll begin with an overview of Mito. If you must work with an
existing DB, you might want to have a look at cl-dbi and clsql. If you
don&amp;rsquo;t need a SQL database and want automatic persistence of Lisp
objects, you also have a choice of libraries.&lt;/p&gt;

&lt;h1 id=&#34;the-mito-orm-and-sxql&#34;&gt;The Mito ORM and SxQL&lt;/h1&gt;

&lt;p&gt;Mito is in Quicklisp:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :mito)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/fukamachi/mito&#34;&gt;Mito&lt;/a&gt; is &amp;ldquo;an ORM for Common Lisp
with migrations, relationships and PostgreSQL support&amp;rdquo;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it &lt;strong&gt;supports MySQL, PostgreSQL and SQLite3&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;when defining a model, it adds an &lt;code&gt;id&lt;/code&gt; (serial primary key),
&lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; fields by default like Ruby&amp;rsquo;s
ActiveRecord or Django,&lt;/li&gt;
&lt;li&gt;handles DB &lt;strong&gt;migrations&lt;/strong&gt; for the supported backends,&lt;/li&gt;
&lt;li&gt;permits DB &lt;strong&gt;schema versioning&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;is tested under SBCL and CCL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an ORM, it allows to write class definitions, to specify
relationships, and provides functions to query the database.  For
custom queries, it relies on
&lt;a href=&#34;https://github.com/fukamachi/sxql&#34;&gt;SxQL&lt;/a&gt;, an SQL generator that
provides the same interface for several backends.&lt;/p&gt;

&lt;p&gt;Working with Mito generally involves these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connecting to the DB&lt;/li&gt;
&lt;li&gt;writing &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;CLOS&lt;/a&gt; classes to define models&lt;/li&gt;
&lt;li&gt;running migrations to create or alter tables&lt;/li&gt;
&lt;li&gt;creating objects, saving same in the DB,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and iterating.&lt;/p&gt;

&lt;h2 id=&#34;connecting-to-a-db&#34;&gt;Connecting to a DB&lt;/h2&gt;

&lt;p&gt;Mito provides the function &lt;code&gt;connect-toplevel&lt;/code&gt; to establish a
connection to RDBMs:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:connect-toplevel :mysql :database-name &amp;quot;myapp&amp;quot; :username &amp;quot;fukamachi&amp;quot; :password &amp;quot;c0mon-1isp&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The driver type can be of &lt;code&gt;:mysql&lt;/code&gt;, &lt;code&gt;:sqlite3&lt;/code&gt; and &lt;code&gt;:postgres&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With sqlite you don&amp;rsquo;t need the username and password:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(connect-toplevel :sqlite3 :database-name &amp;quot;myapp&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As usual, you need to create the MySQL or Postgre database beforehand.
Refer to their documentation.&lt;/p&gt;

&lt;p&gt;Connecting sets &lt;code&gt;mito:*connection*&lt;/code&gt; to the new connection and returns it.&lt;/p&gt;

&lt;p&gt;Disconnect with &lt;code&gt;disconnect-toplevel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;=&amp;gt; you might make good use of a wrapper function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun connect ()
  &amp;quot;Connect to the DB.&amp;quot;
  (connect-toplevel :sqlite3 :database-name &amp;quot;myapp&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;models&#34;&gt;Models&lt;/h2&gt;

&lt;h3 id=&#34;defining-models&#34;&gt;Defining models&lt;/h3&gt;

&lt;p&gt;In Mito, you can define a class which corresponds to a database table
by specifying &lt;code&gt;(:metaclass mito:dao-table-class)&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (or (:varchar 128) :null)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the class automatically adds some slots: a primary key named &lt;code&gt;id&lt;/code&gt;
if there&amp;rsquo;s no primary keys, &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; for
recording timestamps. To disable these behaviors, specify &lt;code&gt;:auto-pk
nil&lt;/code&gt; or &lt;code&gt;:record-timestamps nil&lt;/code&gt; to the defclass forms.&lt;/p&gt;

&lt;p&gt;You can inspect the new class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito.class:table-column-slots (find-class &#39;user))
;=&amp;gt; (#&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS MITO.DAO.MIXIN::ID&amp;gt;
;    #&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::NAME&amp;gt;
;    #&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EMAIL&amp;gt;
;    #&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS MITO.DAO.MIXIN::CREATED-AT&amp;gt;
;    #&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS MITO.DAO.MIXIN::UPDATED-AT&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The class inherits &lt;code&gt;mito:dao-class&lt;/code&gt; implicitly.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find-class &#39;user)
;=&amp;gt; #&amp;lt;MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::USER&amp;gt;

(c2mop:class-direct-superclasses *)
;=&amp;gt; (#&amp;lt;STANDARD-CLASS MITO.DAO.TABLE:DAO-CLASS&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This may be useful when you define methods which can be applied for
all table classes.&lt;/p&gt;

&lt;p&gt;For more information on using the Common Lisp Object System, see the
&lt;a href=&#34;clos.html&#34;&gt;clos&lt;/a&gt; page.&lt;/p&gt;

&lt;h3 id=&#34;creating-the-tables&#34;&gt;Creating the tables&lt;/h3&gt;

&lt;p&gt;After defining the models, you must create the tables:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:ensure-table-exists &#39;user)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So a helper function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun ensure-tables ()
  (mapcar #&#39;mito:ensure-table-exists &#39;(user foo bar)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See
&lt;a href=&#34;https://github.com/fukamachi/mito#generating-table-definitions&#34;&gt;Mito&amp;rsquo;s documentation&lt;/a&gt;
for a couple more ways.&lt;/p&gt;

&lt;p&gt;When you alter the model you&amp;rsquo;ll need to run a DB migration, see the next section.&lt;/p&gt;

&lt;h3 id=&#34;fields&#34;&gt;Fields&lt;/h3&gt;

&lt;h4 id=&#34;fields-types&#34;&gt;Fields types&lt;/h4&gt;

&lt;p&gt;Field types are:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(:varchar &amp;lt;integer&amp;gt;)&lt;/code&gt; ,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:serial&lt;/code&gt;, &lt;code&gt;:bigserial&lt;/code&gt;, &lt;code&gt;:integer&lt;/code&gt;, &lt;code&gt;:bigint&lt;/code&gt;, &lt;code&gt;:unsigned&lt;/code&gt;,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:timestamp&lt;/code&gt;, &lt;code&gt;:timestamptz&lt;/code&gt;,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:bytea&lt;/code&gt;,&lt;/p&gt;

&lt;h4 id=&#34;optional-fields&#34;&gt;Optional fields&lt;/h4&gt;

&lt;p&gt;Use &lt;code&gt;(or &amp;lt;real type&amp;gt; :null)&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;   (email :col-type (or (:varchar 128) :null)
          :initarg :email
          :accessor user-email))
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;field-constraints&#34;&gt;Field constraints&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;:unique-keys&lt;/code&gt; can be used like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We already saw &lt;code&gt;:primary-key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can change the table name with &lt;code&gt;:table-name&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;relationships&#34;&gt;Relationships&lt;/h3&gt;

&lt;p&gt;You can define a relationship by specifying  a foreign class with &lt;code&gt;:col-type&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass tweet ()
  ((status :col-type :text
           :initarg :status
           :accessor tweet-status)
   ;; This slot refers to USER class
   (user :col-type user
         :initarg :user
         :accessor tweet-user))
  (:metaclass mito:dao-table-class))

(table-definition (find-class &#39;tweet))
;=&amp;gt; (#&amp;lt;SXQL-STATEMENT: CREATE TABLE tweet (
;        id BIGSERIAL NOT NULL PRIMARY KEY,
;        status TEXT NOT NULL,
;        user_id BIGINT NOT NULL,
;        created_at TIMESTAMP,
;        updated_at TIMESTAMP
;    )&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can create or retrieve a &lt;code&gt;TWEET&lt;/code&gt; by a &lt;code&gt;USER&lt;/code&gt; object, not a &lt;code&gt;USER-ID&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *user* (mito:create-dao &#39;user :name &amp;quot;Eitaro Fukamachi&amp;quot;))
(mito:create-dao &#39;tweet :user *user*)

(mito:find-dao &#39;tweet :user *user*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Mito doesn&amp;rsquo;t add foreign key constraints for refering tables.&lt;/p&gt;

&lt;h4 id=&#34;one-to-one&#34;&gt;One-to-one&lt;/h4&gt;

&lt;p&gt;A one-to-one relationship is simply represented with a simple foreign
key on a slot (as &lt;code&gt;:col-type user&lt;/code&gt; in the &lt;code&gt;tweet&lt;/code&gt; class). Besides, we
can add a unicity constraint, as with &lt;code&gt;(:unique-keys email)&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&#34;one-to-many-many-to-one&#34;&gt;One-to-many, many-to-one&lt;/h4&gt;

&lt;p&gt;The tweet example above shows a one-to-many relationship between a user and
his tweets: a user can write many tweets, and a tweet belongs to only
one user.&lt;/p&gt;

&lt;p&gt;The relationship is defined with a foreign key on the &amp;ldquo;many&amp;rdquo; side
linking back to the &amp;ldquo;one&amp;rdquo; side. Here the &lt;code&gt;tweet&lt;/code&gt; class defines a
&lt;code&gt;user&lt;/code&gt; foreign key, so a tweet can only have one user. You didn&amp;rsquo;t need
to edit the &lt;code&gt;user&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;A many-to-one relationship is actually the contraty of a one-to-many.
You have to put the foreign key on the approriate side.&lt;/p&gt;

&lt;h4 id=&#34;many-to-many&#34;&gt;Many-to-many&lt;/h4&gt;

&lt;p&gt;A many-to-many relationship needs an intermediate table, which will be
the &amp;ldquo;many&amp;rdquo; side for the two tables it is the intermediary of.&lt;/p&gt;

&lt;p&gt;And, thanks to the join table, we can store more information about the relationship.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s define a &lt;code&gt;book&lt;/code&gt; class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass book ()
    ((title
       :col-type (:varchar 128)
       :initarg :title
       :accessor title)
     (ean
       :col-type (or (:varchar 128) :null)
       :initarg :ean
       :accessor ean))
    (:metaclass mito:dao-table-class))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A user can have many books, and a book (as the title, not the physical
copy) is likely to be in many people&amp;rsquo;s library. Here&amp;rsquo;s the
intermediate class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user-books ()
    ((user
      :col-type user
      :initarg :user)
    (book
      :col-type book
      :initarg :book))
    (:metaclass mito:dao-table-class))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each time we want to add a book to a user&amp;rsquo;s collection (say in
a &lt;code&gt;add-book&lt;/code&gt; function), we create a new &lt;code&gt;user-books&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;But someone may very well own many copies of one book. This is an
information we can store in the join table:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user-books ()
    ((user
      :col-type user
      :initarg :user)
    (book
      :col-type book
      :initarg :book)
    ;; Set the quantity, 1 by default:
    (quantity
      :col-type :integer
      :initarg :quantity
      :initform 1
      :accessor quantity))
    (:metaclass mito:dao-table-class))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;inheritance-and-mixin&#34;&gt;Inheritance and mixin&lt;/h3&gt;

&lt;p&gt;A subclass of DAO-CLASS is allowed to be inherited. This may be useful
when you need classes which have similar columns:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))

(defclass temporary-user (user)
  ((registered-at :col-type :timestamp
                  :initarg :registered-at
                  :accessor temporary-user-registered-at))
  (:metaclass mito:dao-table-class))

(mito:table-definition &#39;temporary-user)
;=&amp;gt; (#&amp;lt;SXQL-STATEMENT: CREATE TABLE temporary_user (
;        id BIGSERIAL NOT NULL PRIMARY KEY,
;        name VARCHAR(64) NOT NULL,
;        email VARCHAR(128) NOT NULL,
;        registered_at TIMESTAMP NOT NULL,
;        created_at TIMESTAMP,
;        updated_at TIMESTAMP,
;        UNIQUE (email)
;    )&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you need a &amp;lsquo;template&amp;rsquo; for tables which doesn&amp;rsquo;t related to any
database tables, you can use &lt;code&gt;DAO-TABLE-MIXIN&lt;/code&gt;. Below the &lt;code&gt;has-email&lt;/code&gt;
class will not create a table.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass has-email ()
  ((email :col-type (:varchar 128)
          :initarg :email
          :accessor object-email))
  (:metaclass mito:dao-table-mixin)
  (:unique-keys email))
;=&amp;gt; #&amp;lt;MITO.DAO.MIXIN:DAO-TABLE-MIXIN COMMON-LISP-USER::HAS-EMAIL&amp;gt;

(defclass user (has-email)
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name))
  (:metaclass mito:dao-table-class))
;=&amp;gt; #&amp;lt;MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::USER&amp;gt;

(mito:table-definition &#39;user)
;=&amp;gt; (#&amp;lt;SXQL-STATEMENT: CREATE TABLE user (
;       id BIGSERIAL NOT NULL PRIMARY KEY,
;       name VARCHAR(64) NOT NULL,
;       email VARCHAR(128) NOT NULL,
;       created_at TIMESTAMP,
;       updated_at TIMESTAMP,
;       UNIQUE (email)
;   )&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See more examples of use in &lt;a href=&#34;https://github.com/fukamachi/mito-auth/&#34;&gt;mito-auth&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h3&gt;

&lt;h4 id=&#34;cannot-change-class-objects-into-class-metaobjects&#34;&gt;&amp;ldquo;Cannot CHANGE-CLASS objects into CLASS metaobjects.&amp;rdquo;&lt;/h4&gt;

&lt;p&gt;If you get the following error message:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Cannot CHANGE-CLASS objects into CLASS metaobjects.
   [Condition of type SB-PCL::METAOBJECT-INITIALIZATION-VIOLATION]
See also:
  The Art of the Metaobject Protocol, CLASS [:initialization]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it is certainly because you first wrote a class definition and &lt;em&gt;then&lt;/em&gt;
added the Mito metaclass and tried to evaluate the class definition
again.&lt;/p&gt;

&lt;p&gt;If this happens, you must remove the class definition from the current package:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (find-class &#39;foo) nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or, with the Slime inspector, click on the class and find the &amp;ldquo;remove&amp;rdquo; button.&lt;/p&gt;

&lt;p&gt;More info &lt;a href=&#34;https://stackoverflow.com/questions/38811931/how-to-change-classs-metaclass&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;migrations&#34;&gt;Migrations&lt;/h2&gt;

&lt;p&gt;First create the tables if needed:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ensure-table-exists &#39;user)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then alter the tables, if needed:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:migrate-table &#39;user)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can check the SQL generated code with &lt;code&gt;migration-expressions
&#39;class&lt;/code&gt;. For example, we create the &lt;code&gt;user&lt;/code&gt; table:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ensure-table-exists &#39;user)
;-&amp;gt; ;; CREATE TABLE IF NOT EXISTS &amp;quot;user&amp;quot; (
;       &amp;quot;id&amp;quot; BIGSERIAL NOT NULL PRIMARY KEY,
;       &amp;quot;name&amp;quot; VARCHAR(64) NOT NULL,
;       &amp;quot;email&amp;quot; VARCHAR(128),
;       &amp;quot;created_at&amp;quot; TIMESTAMP,
;       &amp;quot;updated_at&amp;quot; TIMESTAMP
;   ) () [0 rows] | MITO.DAO:ENSURE-TABLE-EXISTS
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are no changes from the previous user definition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:migration-expressions &#39;user)
;=&amp;gt; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let&amp;rsquo;s add a unique &lt;code&gt;email&lt;/code&gt; field:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The migration will run the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:migration-expressions &#39;user)
;=&amp;gt; (#&amp;lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&amp;gt;
;    #&amp;lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so let&amp;rsquo;s apply it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:migrate-table &#39;user)
;-&amp;gt; ;; ALTER TABLE &amp;quot;user&amp;quot; ALTER COLUMN &amp;quot;email&amp;quot; TYPE character varying(128), ALTER COLUMN &amp;quot;email&amp;quot; SET NOT NULL () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;   ;; CREATE UNIQUE INDEX &amp;quot;unique_user_email&amp;quot; ON &amp;quot;user&amp;quot; (&amp;quot;email&amp;quot;) () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;-&amp;gt; (#&amp;lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&amp;gt;
;    #&amp;lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;queries&#34;&gt;Queries&lt;/h2&gt;

&lt;h3 id=&#34;creating-objects&#34;&gt;Creating objects&lt;/h3&gt;

&lt;p&gt;We can create user objects with the regular &lt;code&gt;make-instance&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar me
  (make-instance &#39;user :name &amp;quot;Eitaro Fukamachi&amp;quot; :email &amp;quot;e.arrows@gmail.com&amp;quot;))
;=&amp;gt; USER
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To save it in DB, use &lt;code&gt;insert-dao&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:insert-dao me)
;-&amp;gt; ;; INSERT INTO `user` (`name`, `email`, `created_at`, `updated_at`) VALUES (?, ?, ?, ?) (&amp;quot;Eitaro Fukamachi&amp;quot;, &amp;quot;e.arrows@gmail.com&amp;quot;, &amp;quot;2016-02-04T19:55:16.365543Z&amp;quot;, &amp;quot;2016-02-04T19:55:16.365543Z&amp;quot;) [0 rows] | MITO.DAO:INSERT-DAO
;=&amp;gt; #&amp;lt;USER {10053C4453}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Do the two steps above at once:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:create-dao &#39;user :name &amp;quot;Eitaro Fukamachi&amp;quot; :email &amp;quot;e.arrows@gmail.com&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should not export the &lt;code&gt;user&lt;/code&gt; class and create objects outside of
its package (it is good practice anyway to keep all database-related
operations in say a &lt;code&gt;models&lt;/code&gt; package and file). You should instead use
a helper function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun make-user (&amp;amp;key name)
  (make-instance &#39;user :name name))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;updating-fields&#34;&gt;Updating fields&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (slot-value me &#39;name) &amp;quot;nitro_idiot&amp;quot;)
;=&amp;gt; &amp;quot;nitro_idiot&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and save it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:save-dao me)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;deleting&#34;&gt;Deleting&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:delete-dao me)
;-&amp;gt; ;; DELETE FROM `user` WHERE (`id` = ?) (1) [0 rows] | MITO.DAO:DELETE-DAO

;; or:
(mito:delete-by-values &#39;user :id 1)
;-&amp;gt; ;; DELETE FROM `user` WHERE (`id` = ?) (1) [0 rows] | MITO.DAO:DELETE-DAO
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;get-the-primary-key-value&#34;&gt;Get the primary key value&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:object-id me)
;=&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;count&#34;&gt;Count&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:count-dao &#39;user)
;=&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;find-one&#34;&gt;Find one&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:find-dao &#39;user :id 1)
;-&amp;gt; ;; SELECT * FROM `user` WHERE (`id` = ?) LIMIT 1 (1) [1 row] | MITO.DB:RETRIEVE-BY-SQL
;=&amp;gt; #&amp;lt;USER {10077C6073}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So here&amp;rsquo;s a possibility of generic helpers to find an object by a given key:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defgeneric find-user (key-name key-value)
  (:documentation &amp;quot;Retrieves an user from the data base by one of the unique
keys.&amp;quot;))

(defmethod find-user ((key-name (eql :id)) (key-value integer))
  (mito:find-dao &#39;user key-value))

(defmethod find-user ((key-name (eql :name)) (key-value string))
  (first (mito:select-dao &#39;user
                          (sxql:where (:= :name key-value)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;find-all&#34;&gt;Find all&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;select-dao&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Get a list of all users:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:select-dao &#39;user)
;=&amp;gt; (#&amp;lt;USER {10077C6073}&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;find-by-relationship&#34;&gt;Find by relationship&lt;/h3&gt;

&lt;p&gt;As seen above:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito:find-dao &#39;tweet :user *user*)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;custom-queries&#34;&gt;Custom queries&lt;/h3&gt;

&lt;p&gt;It is with &lt;code&gt;select-dao&lt;/code&gt; that you can write more precise queries by
giving it &lt;a href=&#34;https://github.com/fukamachi/sxql&#34;&gt;SxQL&lt;/a&gt; statements.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(select-dao &#39;tweet
    (where (:like :status &amp;quot;%Japan%&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;clauses&#34;&gt;Clauses&lt;/h4&gt;

&lt;p&gt;See the &lt;a href=&#34;https://github.com/fukamachi/sxql#sql-clauses&#34;&gt;SxQL documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(select-dao &#39;foo
  (where (:and (:&amp;gt; :age 20) (:&amp;lt;= :age 65))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(order-by :age (:desc :id))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(group-by :sex)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(having (:&amp;gt;= (:sum :hoge) 88))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(limit 0 10)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and &lt;code&gt;join&lt;/code&gt;s, etc.&lt;/p&gt;

&lt;h4 id=&#34;operators&#34;&gt;Operators&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;:not
:is-null, :not-null
:asc, :desc
:distinct
:=, :!=
:&amp;lt;, :&amp;gt;, :&amp;lt;= :&amp;gt;=
:a&amp;lt;, :a&amp;gt;
:as
:in, :not-in
:like
:and, :or
:+, :-, :* :/ :%
:raw
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;triggers&#34;&gt;Triggers&lt;/h2&gt;

&lt;p&gt;Since &lt;code&gt;insert-dao&lt;/code&gt;, &lt;code&gt;update-dao&lt;/code&gt; and &lt;code&gt;delete-dao&lt;/code&gt; are defined as generic
functions, you can define &lt;code&gt;:before&lt;/code&gt;, &lt;code&gt;:after&lt;/code&gt; or &lt;code&gt;:around&lt;/code&gt; methods to those, like regular &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html#qualifiers-and-method-combination&#34;&gt;method combination&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmethod mito:insert-dao :before ((object user))
  (format t &amp;quot;~&amp;amp;Adding ~S...~%&amp;quot; (user-name object)))

(mito:create-dao &#39;user :name &amp;quot;Eitaro Fukamachi&amp;quot; :email &amp;quot;e.arrows@gmail.com&amp;quot;)
;-&amp;gt; Adding &amp;quot;Eitaro Fukamachi&amp;quot;...
;   ;; INSERT INTO &amp;quot;user&amp;quot; (&amp;quot;name&amp;quot;, &amp;quot;email&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;updated_at&amp;quot;) VALUES (?, ?, ?, ?) (&amp;quot;Eitaro Fukamachi&amp;quot;, &amp;quot;e.arrows@gmail.com&amp;quot;, &amp;quot;2016-02-16 21:13:47&amp;quot;, &amp;quot;2016-02-16 21:13:47&amp;quot;) [0 rows] | MITO.DAO:INSERT-DAO
;=&amp;gt; #&amp;lt;USER {100835FB33}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;inflation-deflation&#34;&gt;Inflation/Deflation&lt;/h2&gt;

&lt;p&gt;Inflation/Deflation is a function to convert values between Mito and RDBMS.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass user-report ()
  ((title :col-type (:varchar 100)
          :initarg :title
          :accessor report-title)
   (body :col-type :text
         :initarg :body
         :initform &amp;quot;&amp;quot;
         :accessor report-body)
   (reported-at :col-type :timestamp
                :initarg :reported-at
                :initform (local-time:now)
                :accessor report-reported-at
                :inflate #&#39;local-time:universal-to-timestamp
                :deflate #&#39;local-time:timestamp-to-universal))
  (:metaclass mito:dao-table-class))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;eager-loading&#34;&gt;Eager loading&lt;/h2&gt;

&lt;p&gt;One of the pains in the neck to use ORMs is the &amp;ldquo;N+1 query&amp;rdquo; problem.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; BAD EXAMPLE

(use-package &#39;(:mito :sxql))

(defvar *tweets-contain-japan*
  (select-dao &#39;tweet
    (where (:like :status &amp;quot;%Japan%&amp;quot;))))

;; Getting names of tweeted users.
(mapcar (lambda (tweet)
          (user-name (tweet-user tweet)))
        *tweets-contain-japan*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example sends a query to retrieve a user like &amp;ldquo;SELECT * FROM user
WHERE id = ?&amp;rdquo; at each iteration.&lt;/p&gt;

&lt;p&gt;To prevent this performance issue, add &lt;code&gt;includes&lt;/code&gt; to the above query
which only sends a single WHERE IN query instead of N queries:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; GOOD EXAMPLE with eager loading

(use-package &#39;(:mito :sxql))

(defvar *tweets-contain-japan*
  (select-dao &#39;tweet
    (includes &#39;user)
    (where (:like :status &amp;quot;%Japan%&amp;quot;))))
;-&amp;gt; ;; SELECT * FROM `tweet` WHERE (`status` LIKE ?) (&amp;quot;%Japan%&amp;quot;) [3 row] | MITO.DB:RETRIEVE-BY-SQL
;-&amp;gt; ;; SELECT * FROM `user` WHERE (`id` IN (?, ?, ?)) (1, 3, 12) [3 row] | MITO.DB:RETRIEVE-BY-SQL
;=&amp;gt; (#&amp;lt;TWEET {1003513EC3}&amp;gt; #&amp;lt;TWEET {1007BABEF3}&amp;gt; #&amp;lt;TWEET {1007BB9D63}&amp;gt;)

;; No additional SQLs will be executed.
(tweet-user (first *))
;=&amp;gt; #&amp;lt;USER {100361E813}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;schema-versioning&#34;&gt;Schema versioning&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;$ ros install mito
$ mito
Usage: mito command [option...]

Commands:
    generate-migrations
    migrate

Options:
    -t, --type DRIVER-TYPE          DBI driver type (one of &amp;quot;mysql&amp;quot;, &amp;quot;postgres&amp;quot; or &amp;quot;sqlite3&amp;quot;)
    -d, --database DATABASE-NAME    Database name to use
    -u, --username USERNAME         Username for RDBMS
    -p, --password PASSWORD         Password for RDBMS
    -s, --system SYSTEM             ASDF system to load (several -s&#39;s allowed)
    -D, --directory DIRECTORY       Directory path to keep migration SQL files (default: &amp;quot;/Users/nitro_idiot/Programs/lib/mito/db/&amp;quot;)
    --dry-run                       List SQL expressions to migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;introspection&#34;&gt;Introspection&lt;/h2&gt;

&lt;p&gt;Mito provides some functions for introspection.&lt;/p&gt;

&lt;p&gt;We can access the information of &lt;strong&gt;columns&lt;/strong&gt; with the functions in
&lt;code&gt;(mito.class.column:...)&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;table-column-[class, name, info, not-null-p,...]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primary-key-p&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and likewise for &lt;strong&gt;tables&lt;/strong&gt; with &lt;code&gt;(mito.class.table:...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Given we get a list of slots of our class:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;closer-mop&amp;quot;)

(closer-mop:class-direct-slots (find-class &#39;user))
;; (#&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS NAME&amp;gt;
;;  #&amp;lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS EMAIL&amp;gt;)

(defparameter user-slots *)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can answer the following questions:&lt;/p&gt;

&lt;h3 id=&#34;what-is-the-type-of-this-column&#34;&gt;What is the type of this column ?&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito.class.column:table-column-type (first user-slots))
;; (:VARCHAR 64)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;is-this-column-nullable&#34;&gt;Is this column nullable ?&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(mito.class.column:table-column-not-null-p
  (first user-slots))
;; T
(mito.class.column:table-column-not-null-p
  (second user-slots))
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;testing&#34;&gt;Testing&lt;/h2&gt;

&lt;p&gt;We don&amp;rsquo;t want to test DB operations against the production one. We
need to create a temporary DB before each test.&lt;/p&gt;

&lt;p&gt;The macro below creates a temporary DB with a random name, creates the
tables, runs the code and connects back to the original DB connection.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun random-string (length)
  ;; thanks 40ants/hacrm.
  (let ((chars &amp;quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&amp;quot;))
    (coerce (loop repeat length
                  collect (aref chars (random (length chars))))
            &#39;string)))

(defmacro with-empty-db (&amp;amp;body body)
  &amp;quot;Run `body` with a new temporary DB.
  &amp;quot;
  `(let* ((*random-state* (make-random-state t))
          (prefix (concatenate &#39;string
                               (random-string 8)
                               &amp;quot;/&amp;quot;))
          (connection mito:*connection*))
     (uiop:with-temporary-file (:pathname name :prefix prefix)
       (let* ((*db-name* name)
              (*db* (connect)))
         (ensure-tables-exist)
         (migrate-all)
         ,@body
         (setf mito:*connection* connection)
         (connect)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(prove:subtest &amp;quot;Creation in a temporary DB.&amp;quot;
  (with-empty-db
    (let ((user (make-user :name &amp;quot;Cookbook&amp;quot;)))
      (save-user user)

      (prove:is (name user)
                &amp;quot;Cookbook&amp;quot;
                &amp;quot;Test username in a temp DB.&amp;quot;))))
;; Creation in a temporary DB
;;  CREATE TABLE &amp;quot;user&amp;quot; (
;;       id BIGSERIAL NOT NULL PRIMARY KEY,
;;       name VARCHAR(64) NOT NULL,
;;       email VARCHAR(128) NOT NULL,
;;       created_at TIMESTAMP,
;;       updated_at TIMESTAMP,
;;       UNIQUE (email)
;; ) () [0 rows] | MITO.DB:EXECUTE-SQL
;; ✓ Test username in a temp DB.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/mito-attachment&#34;&gt;mito-attachment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/mito-auth&#34;&gt;mito-auth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/can/&#34;&gt;can&lt;/a&gt; a role-based access right control library&lt;/li&gt;
&lt;li&gt;an advanced &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/assets/defmodel.lisp&#34;&gt;&amp;ldquo;defmodel&amp;rdquo; macro&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- # todo: Generating models for an existing DB --&gt;
</description>
    </item>
    
    <item>
      <title>These months in Common Lisp: Q1 2018</title>
      <link>/blog/these-months-in-common-lisp-q1-2018/</link>
      <pubDate>Sun, 01 Apr 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/these-months-in-common-lisp-q1-2018/</guid>
      <description>

&lt;h1 id=&#34;documentation&#34;&gt;Documentation&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;Multidimensional arrays – the Common Lisp Cookbook&#34;&gt;Multidimensional arrays – the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/error_handling.html&#34;&gt;Error and condition handling - the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html&#34;&gt;Scripting: parsing command line arguments, building self-contained executables - the Common Lisp Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.common-lisp.net/asdf/asdf/blob/master/doc/best_practices.md&#34;&gt;ASDF Best Practices for 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/01/the-quicklisp-local-projects-mechanism.html&#34;&gt;The Quicklisp local-projects mechanism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/roswell/roswell/wiki/How-to-distribute-your-software,-not-library,-on-Quicklisp-ala-python-pip&#34;&gt;How to distribute your software, not library, on Quicklisp ala python pip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://commonlispbr.github.io/&#34;&gt;Common Lisp Brazil Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/azzamsa/awesome-lisp-companies&#34;&gt;Awesome Lisp companies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7jk0co/announcing_quickref_a_global_documentation/&#34;&gt;Announcing Quickref: a global documentation project for Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;announcements&#34;&gt;Announcements&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://european-lisp-symposium.org/2018/index.html&#34;&gt;European Lisp Symposium 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://itch.io/jam/lisp-game-jam-2018&#34;&gt;Lisp Game Jam 2018&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;projects&#34;&gt;Projects&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/next-browser/next&#34;&gt;Next web browser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/koji-kojiro/cl-repl&#34;&gt;cl-repl, the Common Lisp ipython-like REPL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/emotiq/emotiq&#34;&gt;Emotiq - blockchain in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reddit-archive/reddit1.0&#34;&gt;original reddit code&lt;/a&gt; from 2005. &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/88513q/original_reddit_code_from_2005/&#34;&gt;reddit&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sjl.bitbucket.io/temperance/&#34;&gt;Temperance - logic programming (in development, reached v1.0.0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/jnjcc/cl-qrencode&#34;&gt;QR code 2005 encoder in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/print-licenses&#34;&gt;print-licences: print licenses used by the given project and its dependencies (from sjl and dk_jackdaniel&amp;rsquo;s utils)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/privet-kitty/dufy&#34;&gt;Dufy, color library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/borodust/cl-flow/&#34;&gt;cl-flow&lt;/a&gt; - Data-flowish computation tree library for non-blocking concurrent Common Lisp.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/r/eshamster/cl-devel2/&#34;&gt;A docker container for CL development&lt;/a&gt; (also &lt;a href=&#34;https://hub.docker.com/r/daewok/lisp-devel/&#34;&gt;lisp-devel&lt;/a&gt;, &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci&#34;&gt;CI on CL Cookbook&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/svspire/quickfork&#34;&gt;Quickfork - Quicklisp for teams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apache/thrift/commits/master&#34;&gt;Apache Thrift gains CL support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/t-cool/jscl-playground&#34;&gt;JSCL playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/rigetticomputing/magicl&#34;&gt;MAGICL: Matrix Algebra proGrams In Common Lisp - Rigetti Computing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/BusFactor1Inc/eturia&#34;&gt;Eturia has been open-sourced. An Open Computer for Education for teaching #Lisp written in #Javascript. &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/02/quicklisp-dist-update-for-february-2018.html&#34;&gt;Quicklisp dist update for february 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.sbcl.org/all-news.html#1.4.5&#34;&gt;SBCL 1.4.5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/portacle/portacle/releases/tag/1.1&#34;&gt;Portacle 1.1 release: SBCL update, ASDF fixes &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/mcclim/posts/McCLIM-097-Imbolc-release.html&#34;&gt;McCLIM 0.9.7 &amp;ldquo;Imbolc&amp;rdquo; release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/norvig/paip-lisp&#34;&gt;Peter Norvig&amp;rsquo;s Paradigms of Artificial Intelligence Programming - book as pdf and lisp code on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;cl-torrents 0.9 - readline interface and 1337x.to scraper&#34;&gt;cl-torrents 0.9 - readline interface and 1337x.to scraper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Discoveries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mikelevins/folio2&#34;&gt;Folio2 - a collection of small libraries that provide support for functional idioms and data structures in Common Lisp; seamless integration of Series and FSet &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plkrueger/CommonLispFred&#34;&gt;Lisp Interface to Federal Reserve Economic Data (FRED®)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.common-lisp.net/ansi-test/cl-bench&#34;&gt;cl-bench&lt;/a&gt; benchmarking tool. &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/882mz4/clbench_common_lisp_benchmarking_suite/&#34;&gt;reddit&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nikodemus/screamer&#34;&gt;Screamer - nondeterministic programming. Augment Common Lisp with practically all of the functionality of both Prolog and constraint logic programming languages (10 yo, Nikodemus)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7oaum4/cmera_a_commonlisp_sourcetosource_compiler_to/&#34;&gt;C-Mera, a Common Lisp source-to-source compiler to generate C/C++&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7nf4an/regex_regular_expression_library_in_common_lisp/&#34;&gt;Regex, regular expression library in Common Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7mji50/cells_spreadsheetlike_expressiveness_for_clos/&#34;&gt;Cells, spreadsheet-like expressiveness for CLOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;articles&#34;&gt;Articles&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://notes.eatonphil.com/starting-a-minimal-common-lisp-project.html&#34;&gt;Starting a minimal Common Lisp project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.teknik.io/phoe/p/1633&#34;&gt;Emacs + ECL on Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/&#34;&gt;Generic, consistent and dotted access of data structures with Access - lisp-journey&lt;/a&gt; (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7pysmx/generic_consistent_and_dotted_access_of_data/&#34;&gt;reddit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/01/build-failure-rss-feeds.html&#34;&gt;Quicklisp&amp;rsquo;s per-project build failures RSS feed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://blog.quicklisp.org/2018/02/quicklisp-implementation-stats-for-2017.html&#34;&gt;Quicklisp implementation stats for 2017+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://turtleware.eu/posts/cl-charms-crash-course.html&#34;&gt;cl-charms crash course&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@MartinCracauer/llvms-garbage-collection-facilities-and-sbcl-s-generational-gc-a13eedfb1b31&#34;&gt;LLVM’s garbage collection facilities and SBCL’s generational GC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/blog/snippets-functional-style-more/&#34;&gt;A bunch of utilities from (again) sjl: higher order functions, sequences, debugging, profiling.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://common-lisp.net/project/mcclim/posts/Sheets-as-ideal-forms.html&#34;&gt;Sheets as ideal forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://langnostic.inaimathi.ca/posts/the-return-of-cl-notebook&#34;&gt;The return of cl-notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7rsfyn/testing_the_series_common_lisp_package/&#34;&gt;Testing the SERIES package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;discussion&#34;&gt;Discussion&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=16591592&#34;&gt;Portacle hits #1 on Hackernews&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7n90l4/what_do_you_plan_to_work_on_in_2018/&#34;&gt;What do you plan to work on in 2018?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/87gyhq/pros_and_cons_of_different_ways_to_declare_types/&#34;&gt;Pros and cons of different ways to declare types in Common Lisp?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7z7wuq/has_anyone_considered_or_started_a_project_to/&#34;&gt;Has anyone considered or started a project to write a CL implementation in WebAssembly?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7s53qi/what_do_you_recommend_to_work_with_sql_databases/&#34;&gt;What do you recommend to work with SQL databases ? What&amp;rsquo;s your experience with Mito ?&lt;/a&gt; and &lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7ozdcf/sqliteonly_interface_clsqlite_or_cldbi/&#34;&gt;sqlite only interface: cl-sqlite or cl-dbi ?&lt;/a&gt;
and &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7iebty/ask_rlisp_is_there_any_lightweight_orm_that/&#34;&gt;is there an ORM that generates classes from table definitions ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/82wiyt/how_to_collect_all_asdf_dependencies_for/&#34;&gt;How to get asdf system dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/8665ga/please_join_the_cltelegrambot_refactoring_effort/&#34;&gt;Join the cl-telegraph-bot refactoring effort !&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/86mbhc/gui_development_done_in_lisp_2013_comment/&#34;&gt;GUI development done in Lisp (2013 comment)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/88f9qs/strategies_for_dealing_with_large_amounts_of/&#34;&gt;Strategies for Dealing with Large Amounts of Memory in Lisp? (SBCL)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7xizfr/gui_embedded_plots_in_lisp/&#34;&gt;GUI embedded plots in Lisp ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7sp8mo/is_there_any_nonlisp_that_copies_common_lisps/&#34;&gt;Is there any non-lisp that copies Common Lisp&amp;rsquo;s condition system?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;common-lisp-vs&#34;&gt;Common Lisp VS &amp;hellip;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/86ze0t/as_a_newbie_what_i_will_miss_if_i_choose_racket/&#34;&gt;As a newbie, what I will miss if I choose Racket over Common Lisp? Or if I happen to learn both at somepoint in future, choosing Racket/Common Lisp now would make sense?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7lf149/what_can_other_languages_do_that_lisp_cant/&#34;&gt;What can other languages do that Lisp can&amp;rsquo;t ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;screencasts&#34;&gt;Screencasts&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://youtu.be/unFYp6QFEiU?t=9m4s&#34;&gt;Pushing Pixels with Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://events.tymoon.eu/1?20180311&#34;&gt;Lisp Treehouse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=G2hgarXaEJI&#34;&gt;Common Lisp study group 01-30-2018&lt;/a&gt; (video)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/playlist?list=PL2VAYZE_4wRJi_vgpjsH75kMhN4KsuzR_&#34;&gt;Little bits of Lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;jobs&#34;&gt;Jobs&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.mail-archive.com/types-announce@lists.seas.upenn.edu/msg06942.html&#34;&gt;Research Scientist Interactive Theorem Proving (using PVS, a Common Lisp application)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispjobs.wordpress.com/2017/11/22/lisp-engineer-mind-ai-seoul-korea-l-a-usa/&#34;&gt;Lisp Engineer, Mind.ai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://angel.co/l/2717mK&#34;&gt;lisp-based domain specific language, compiler design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7ik44o/seeking_cofounder_for_lisp_game_studio/&#34;&gt;Seeking co-founder for Lisp game studio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;If we missed anything: &lt;a href=&#34;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io&#34;&gt;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tip: capture standard and error output</title>
      <link>/blog/tip-capture-all-standard-output/</link>
      <pubDate>Tue, 06 Mar 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/tip-capture-all-standard-output/</guid>
      <description>&lt;p&gt;What if we want to capture standard (and/or error) output in order to
ignore it or post-process it ? It&amp;rsquo;s very simple, a
&lt;a href=&#34;https://stackoverflow.com/questions/35333715/lisp-capture-stdout-and-stderr-store-it-in-separate-variables&#34;&gt;little search&lt;/a&gt;
and we&amp;rsquo;re good:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((*standard-output* (make-string-output-stream))
      (*error-output* (make-string-output-stream)))
  (apply function args) ;; anything
  (setf standard-output (get-output-stream-string *standard-output*)))
(print-results standard-output))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and now in &lt;code&gt;print-results&lt;/code&gt; we can print to standard output without
being intercepted (and in our case, we&amp;rsquo;ll highlight some user-defined
keywords).&lt;/p&gt;

&lt;p&gt;Above, just don&amp;rsquo;t forget to get the output content with
&lt;code&gt;(get-output-stream-string *standard-output*)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A thing to note is that if your app printed stuff on error output and
standard output consecutively, now it will print all standard output
as a single block.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;edit&lt;/strong&gt;) Of course, &lt;code&gt;with-output-to-string&lt;/code&gt; is simpler to capture one stream:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf standard-output (with-output-to-string (*standard-output*)
                        (apply function args)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;edit 2&lt;/strong&gt;, thanks to &lt;a href=&#34;https://www.reddit.com/r/learnlisp/comments/837i0j/tip_capture_standard_and_error_output/&#34;&gt;redditers&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;Don&amp;rsquo;t bind &lt;em&gt;&lt;code&gt;standard-output&lt;/code&gt;&lt;/em&gt; directly; bind the string stream to a
lexical, then bind &lt;code&gt;*standard-output*&lt;/code&gt; to that:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-output-to-string (s)
  (let ((*standard-output* s)) (write-string &amp;quot;abc&amp;quot;)))
-&amp;gt; &amp;quot;abc&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let&amp;rsquo;s bind both &lt;code&gt;*standard-output*&lt;/code&gt; and &lt;code&gt;*standard-error*&lt;/code&gt; to s:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-output-to-string (s)
  (let ((*standard-output* s)
        (*standard-error* s))
    (write-string &amp;quot;abc&amp;quot;)
    (write-string &amp;quot;def&amp;quot; *standard-error*)))
-&amp;gt; &amp;quot;abcdef&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Eliminate s and just bind &lt;code&gt;*standard-output*&lt;/code&gt; and then tie
&lt;code&gt;*standard-error*&lt;/code&gt; to the same stream:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-output-to-string (*standard-output*)
  (let ((*standard-error* *standard-output*))
    (write-string &amp;quot;abc&amp;quot;)
    (write-string &amp;quot;def&amp;quot; *standard-error*)))
--&amp;gt; &amp;quot;abcdef&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The conclusion stays: it&amp;rsquo;s handy and easy :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fixing a CL21 error message in an unrelated library after a quicklisp update (it&#39;s about cache)</title>
      <link>/blog/fixing-a-cl21-error-message-after-quicklisp-update/</link>
      <pubDate>Mon, 12 Feb 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/fixing-a-cl21-error-message-after-quicklisp-update/</guid>
      <description>&lt;p&gt;I just updated my Quicklisp dist and suddenly couldn&amp;rsquo;t load some
libraries any more. I got an error related to cl21 looking like the one below
(I didn&amp;rsquo;t note the exact message sorry), even though the library was
unrelate to cl21 (it was about osicat and cffi.grovel):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;couldn&amp;rsquo;t find adjustable-vectors from CL21.core.arrays&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you skip through the restarts you&amp;rsquo;ll see mentions of a cache in
&lt;code&gt;~/.cache/common-lisp/sbclxx-xx/quicklisp/…&lt;/code&gt;. It contains the compiled &lt;code&gt;.fasl&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;I deleted this cache and I&amp;rsquo;m good to go.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;related: &lt;a href=&#34;https://github.com/cl21/cl21/issues/99&#34;&gt;https://github.com/cl21/cl21/issues/99&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>(bookmark) Get a list of all the dependencies of a lisp system</title>
      <link>/blog/bookmark-get-a-list-of-dependencies-of-a-lisp-system/</link>
      <pubDate>Tue, 23 Jan 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/bookmark-get-a-list-of-dependencies-of-a-lisp-system/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ll save here
&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/82wiyt/how_to_collect_all_asdf_dependencies_for/&#34;&gt;a reddit discussion&lt;/a&gt;,
which I find interesting but that will be burried quickly down
reddit&amp;rsquo;s history. The goal is to &lt;strong&gt;get all the dependencies of a
system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;d better read the OP&amp;rsquo;s question and the discussion (where the OP
is the experimented &lt;a href=&#34;https://github.com/40ants/&#34;&gt;svetlyak40wt/40ants&lt;/a&gt;,
at the moment doing a god&amp;rsquo;s work on Weblocks).&lt;/p&gt;

&lt;p&gt;His solution is &lt;a href=&#34;https://gist.github.com/svetlyak40wt/03bc68c820bb3e45bc7871870379c42e&#34;&gt;https://gist.github.com/svetlyak40wt/03bc68c820bb3e45bc7871870379c42e&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :fset)

(defun get-dependencies (system)
  &amp;quot;Returns a set with all dependencies of a given system.
   System should be loaded first.&amp;quot;
  (labels ((normalize (name)
             (etypecase name
               (string (string-downcase name))
               (symbol (normalize (symbol-name name)))
               (list
                (let ((dep-type (first name))
                      (supported-dep-types (list :version :feature :require)))
                  (unless (member dep-type
                                  supported-dep-types)
                    (error &amp;quot;This component \&amp;quot;~A\&amp;quot; should have first element from this list: ~A.&amp;quot;
                           name
                           supported-dep-types))

                  (normalize
                   (case dep-type
                     (:version (second name))
                     (:feature (third name))
                     (:require (second name)))))))))

    (let ((processed (fset:set))
          (queue (fset:set (normalize system))))

      (do ((current-name (fset:arb queue)
                         (fset:arb queue)))
          ((null current-name)
           ;; return result
           processed)

        ;; Remove current name from the queue
        (setf queue
              (fset:less queue current-name))
        ;; And put it into the &amp;quot;processed&amp;quot; pool
        (setf processed
              (fset:with processed current-name))

        ;; And add it&#39;s dependencies which aren&#39;t processed or in the queue already
        ;; Sometimes system can&#39;t be found because itself depends on some feature,
        ;; for example, you can specify dependency as a list:
        ;; (:FEATURE :SBCL (:REQUIRE :SB-INTROSPECT))
        ;; and it will be loaded only on SBCL.
        ;; When we are collecting dependencies on another implementation,
        ;; we don&#39;t want to fail with an error because ASDF is unable to find
        ;; such dependencies
        (let* ((system (ignore-errors
                        (asdf:find-system current-name)))
               (deps (when system
                       (asdf:component-sideway-dependencies system))))
          (dolist (dep deps)
            (let ((normalized-dep (normalize dep)))
              (unless (or (fset:lookup processed normalized-dep)
                          (fset:lookup queue normalized-dep))
                (setf queue
                      (fset:with queue normalized-dep)))))))

      (values processed))))

#|
DEPENDENCIES&amp;gt; (ql:quickload :clinch)
DEPENDENCIES&amp;gt; (get-dependencies :clinch)
#{
  &amp;quot;cffi&amp;quot;
  &amp;quot;sdl2&amp;quot;
  &amp;quot;uiop&amp;quot;
  &amp;quot;babel&amp;quot;
  &amp;quot;swank&amp;quot;
  &amp;quot;clinch&amp;quot;
  &amp;quot;cl-glut&amp;quot;
  &amp;quot;cl-json&amp;quot;
  &amp;quot;cl-ppcre&amp;quot;
  &amp;quot;rtg-math&amp;quot;
  &amp;quot;cl-opengl&amp;quot;
  &amp;quot;cl-plus-c&amp;quot;
  &amp;quot;alexandria&amp;quot;
  &amp;quot;cl-autowrap&amp;quot;
  &amp;quot;glsl-symbols&amp;quot;
  &amp;quot;defpackage-plus&amp;quot;
  &amp;quot;trivial-garbage&amp;quot;
  &amp;quot;trivial-timeout&amp;quot;
  &amp;quot;bordeaux-threads&amp;quot;
  &amp;quot;trivial-channels&amp;quot;
  &amp;quot;trivial-features&amp;quot; }
|#
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&amp;rsquo;s also &lt;code&gt;(ql-dist:dependency-tree &amp;quot;mgl&amp;quot;)&lt;/code&gt; which has limitations
though, it&amp;rsquo;s only for Quicklisp projects and doesn&amp;rsquo;t work with
everything (see the thread).&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s all folks !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>snippets - functional style, sequences, debugging and more utilities</title>
      <link>/blog/snippets-functional-style-more/</link>
      <pubDate>Tue, 23 Jan 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/snippets-functional-style-more/</guid>
      <description>

&lt;p&gt;From
&lt;a href=&#34;https://github.com/sjl/cl-losh/blob/master/losh.lisp&#34;&gt;sjl&amp;rsquo;s utilities&lt;/a&gt;
(thanks so much for the nice docstrings). The goal here is to read
some code and learn about (hidden) gems.&lt;/p&gt;

&lt;p&gt;The following snippets should be copy-pastable. They are the ones I
find most interesting, I left some behind.&lt;/p&gt;

&lt;p&gt;To reduce the dependency load, Alexandria or Quickutil functions can
be imported one by one with &lt;a href=&#34;http://quickutil.org/&#34;&gt;Quickutil&lt;/a&gt;.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#higher-order-functions&#34;&gt;Higher order functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sequences&#34;&gt;Sequences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#debugging-and-logging&#34;&gt;Debugging and logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#profiling-with-sbcl&#34;&gt;Profiling (with SBCL)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;higher-order-functions&#34;&gt;Higher order functions&lt;/h2&gt;

&lt;p&gt;See also &lt;a href=&#34;https://github.com/mikelevins/folio2&#34;&gt;https://github.com/mikelevins/folio2&lt;/a&gt; and &lt;a href=&#34;/blog/functional-programming-in-common-lisp/&#34;&gt;How to do functional programming in CL&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun juxt (&amp;amp;rest functions)
  &amp;quot;Return a function that will juxtapose the results of `functions`.
  This is like Clojure&#39;s `juxt`.  Given functions `(f0 f1 ... fn)`, this will
  return a new function which, when called with some arguments, will return
  `(list (f0 ...args...) (f1 ...args...) ... (fn ...args...))`.
  Example:
    (funcall (juxt #&#39;list #&#39;+ #&#39;- #&#39;*) 1 2)
    =&amp;gt; ((1 2) 3 -1 2)
  &amp;quot;
  (lambda (&amp;amp;rest args)
    (mapcar (alexandria:rcurry #&#39;apply args) functions)))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun nullary (function &amp;amp;optional result)
  &amp;quot;Return a new function that acts as a nullary-patched version of `function`.
  The new function will return `result` when called with zero arguments, and
  delegate to `function` otherwise.
  Examples:
    (max 1 10 2) ; =&amp;gt; 10
    (max)        ; =&amp;gt; invalid number of arguments
    (funcall (nullary #&#39;max))          ; =&amp;gt; nil
    (funcall (nullary #&#39;max 0))        ; =&amp;gt; 0
    (funcall (nullary #&#39;max 0) 1 10 2) ; =&amp;gt; 10
    (reduce #&#39;max nil)                  ; =&amp;gt; invalid number of arguments
    (reduce (nullary #&#39;max) nil)        ; =&amp;gt; nil
    (reduce (nullary #&#39;max :empty) nil) ; =&amp;gt; :empty
    (reduce (nullary #&#39;max) &#39;(1 10 2))  ; =&amp;gt; 10
  &amp;quot;
  (lambda (&amp;amp;rest args)
    (if (null args) result (apply function args))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro gathering (&amp;amp;body body)
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L515
  &amp;quot;Run `body` to gather some things and return a fresh list of them.
  `body` will be executed with the symbol `gather` bound to a function of one
  argument.  Once `body` has finished, a list of everything `gather` was called
  on will be returned.
  It&#39;s handy for pulling results out of code that executes procedurally and
  doesn&#39;t return anything, like `maphash` or Alexandria&#39;s `map-permutations`.
  The `gather` function can be passed to other functions, but should not be
  retained once the `gathering` form has returned (it would be useless to do so
  anyway).
  Examples:
    (gathering
      (dotimes (i 5)
        (gather i))
    =&amp;gt;
    (0 1 2 3 4)
    (gathering
      (mapc #&#39;gather &#39;(1 2 3))
      (mapc #&#39;gather &#39;(a b)))
    =&amp;gt;
    (1 2 3 a b)
  &amp;quot;
  (with-gensyms (result)
    `(let ((,result (make-queue)))
      (flet ((gather (item)
               (enqueue item ,result)))
        (declare (dynamic-extent #&#39;gather))
        ,@body)
      (queue-contents ,result))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we need the &lt;code&gt;queue&lt;/code&gt; struct.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct (queue (:constructor make-queue))
  (contents nil :type list)
  (last nil :type list)
  (size 0 :type fixnum))

;; real code is richer, with inline and inlinable function declarations.

(defun make-queue ()
  &amp;quot;Allocate and return a fresh queue.&amp;quot;
  (make-queue%))

(defun queue-empty-p (queue)
  &amp;quot;Return whether `queue` is empty.&amp;quot;
  (zerop (queue-size queue)))

(defun enqueue (item queue)
  &amp;quot;Enqueue `item` in `queue`, returning the new size of the queue.&amp;quot;
  (let ((cell (cons item nil)))
    (if (queue-empty-p queue)
      (setf (queue-contents queue) cell)
      (setf (cdr (queue-last queue)) cell))
    (setf (queue-last queue) cell))
  (incf (queue-size queue)))

(defun dequeue (queue)
  &amp;quot;Dequeue an item from `queue` and return it.&amp;quot;
  (when (zerop (decf (queue-size queue)))
    (setf (queue-last queue) nil))
  (pop (queue-contents queue)))

(defun queue-append (queue list)
  &amp;quot;Enqueue each element of `list` in `queue` and return the queue&#39;s final size.&amp;quot;
  (loop :for item :in list
        :for size = (enqueue item queue)
        :finally (return size)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;sequences&#34;&gt;Sequences&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun frequencies (sequence &amp;amp;key (test &#39;eql))
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L1910
  &amp;quot;Return a hash table containing the frequencies of the items in `sequence`.
  Uses `test` for the `:test` of the hash table.
  Example:
    (frequencies &#39;(foo foo bar))
    =&amp;gt; {foo 2
        bar 1}
  &amp;quot;
  (iterate
    (with result = (make-hash-table :test test))
    (for i :in-whatever sequence)
    (incf (gethash i result 0))
    (finally (return result))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun proportions (sequence &amp;amp;key (test &#39;eql) (float t))
  &amp;quot;Return a hash table containing the proportions of the items in `sequence`.
  Uses `test` for the `:test` of the hash table.
  If `float` is `t` the hash table values will be coerced to floats, otherwise
  they will be left as rationals.
  Example:
    (proportions &#39;(foo foo bar))
    =&amp;gt; {foo 0.66666
        bar 0.33333}
    (proportions &#39;(foo foo bar) :float nil)
    =&amp;gt; {foo 2/3
        bar 1/3}
  &amp;quot;
  (let* ((freqs (frequencies sequence :test test))
         (total (reduce #&#39;+ (hash-table-values freqs)
                        :initial-value (if float 1.0 1))))
    (mutate-hash-values (lambda (v) (/ v total))
                        freqs)))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun group-by (function sequence &amp;amp;key (test #&#39;eql) (key #&#39;identity))
  &amp;quot;Return a hash table of the elements of `sequence` grouped by `function`.
  This function groups the elements of `sequence` into buckets.  The bucket for
  an element is determined by calling `function` on it.
  The result is a hash table (with test `test`) whose keys are the bucket
  identifiers and whose values are lists of the elements in each bucket.  The
  order of these lists is unspecified.
  If `key` is given it will be called on each element before passing it to
  `function` to produce the bucket identifier.  This does not effect what is
  stored in the lists.
  Examples:
    (defparameter *items* &#39;((1 foo) (1 bar) (2 cats) (3 cats)))
    (group-by #&#39;first *items*)
    ; =&amp;gt; { 1 ((1 foo) (1 bar))
    ;      2 ((2 cats))
    ;      3 ((3 cats)) }
    (group-by #&#39;second *items*)
    ; =&amp;gt; { foo  ((1 foo))
    ;      bar  ((1 bar))
    ;      cats ((2 cats) (3 cats)) }
    (group-by #&#39;evenp *items* :key #&#39;first)
    ; =&amp;gt; { t   ((2 cats))
    ;      nil ((1 foo) (1 bar) (3 cats)) }
  &amp;quot;
  (iterate
    (with result = (make-hash-table :test test))
    (for i :in-whatever sequence)
    (push i (gethash (funcall function (funcall key i)) result))
    (finally (return result))))


(defun take-list (n list)
  (iterate (declare (iterate:declare-variables))
           (repeat n)
           (for item :in list)
           (collect item)))

(defun take-seq (n seq)
  (subseq seq 0 (min n (length seq))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro do-repeat (n &amp;amp;body body)
  &amp;quot;Perform `body` `n` times.&amp;quot;
  `(dotimes (,(gensym) ,n)
     ,@body))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro do-range (ranges &amp;amp;body body)
  &amp;quot;Perform `body` on the given `ranges`.

  Each range in `ranges` should be of the form `(variable from below)`.  During
  iteration `body` will be executed with `variable` bound to successive values
  in the range [`from`, `below`).

  If multiple ranges are given they will be iterated in a nested fashion.

  Example:

    (do-range ((x  0  3)
               (y 10 12))
      (pr x y))
    ; =&amp;gt;
    ; 0 10
    ; 0 11
    ; 1 10
    ; 1 11
    ; 2 10
    ; 2 11

  &amp;quot;
  (if (null ranges)
    `(progn ,@body)
    (destructuring-bind (var from below) (first ranges)
      `(loop :for ,var :from ,from :below ,below
             :do (do-range ,(rest ranges) ,@body)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun enumerate (sequence &amp;amp;key (start 0) (step 1) key)
  &amp;quot;Return an alist of `(n . element)` for each element of `sequence`.
  `start` and `step` control the values generated for `n`, NOT which elements of
  the sequence are enumerated.
  Examples:
    (enumerate &#39;(a b c))
    ; =&amp;gt; ((0 . A) (1 . B) (2 . C))
    (enumerate &#39;(a b c) :start 1)
    ; =&amp;gt; ((1 . A) (2 . B) (3 . C))
    (enumerate &#39;(a b c) :key #&#39;ensure-keyword)
    ; =&amp;gt; ((0 . :A) (1 . :B) (2 . :C))
  &amp;quot;
  (iterate (for el :in-whatever sequence)
           (for n :from start :by step)
           (collect (cons n (if key
                              (funcall key el)
                              el)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;uses &lt;code&gt;iterate&lt;/code&gt;, on Quicklisp (see also Shinmera&amp;rsquo;s &lt;a href=&#34;https://github.com/Shinmera/for&#34;&gt;For&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The following&lt;code&gt;take&lt;/code&gt; is taken from &lt;a href=&#34;https://github.com/TBRSS/serapeum/&#34;&gt;Serapeum&lt;/a&gt; (also available in CL21).&lt;/p&gt;

&lt;p&gt;The original helpers (take-list, etc) are originally inlined for optimal performance
with a custom &amp;ldquo;defun-inline&amp;rdquo;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun take (n seq)
  &amp;quot;Return a fresh sequence of the first `n` elements of `seq`.
  The result will be of the same type as `seq`.
  If `seq` is shorter than `n` a shorter result will be returned.
  Example:
    (take 2 &#39;(a b c))
    =&amp;gt; (a b)
    (take 4 #(1))
    =&amp;gt; #(1)
  From Serapeum.
  &amp;quot;
  (check-type n array-index)
  (ctypecase seq
    (list (take-list n seq))
    (sequence (take-seq n seq))))

(defun take-list (n list)
  (iterate (declare (iterate:declare-variables))
           (repeat n)
           (for item :in list)
           (collect item)))

(defun take-seq (n seq)
  (subseq seq 0 (min n (length seq))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun take-while-list (predicate list)
  (iterate (for item :in list)
           (while (funcall predicate item))
           (collect item)))

(defun take-while-seq (predicate seq)
  (subseq seq 0 (position-if-not predicate seq)))

(defun take-while (predicate seq)
  &amp;quot;Take elements from `seq` as long as `predicate` remains true.
  The result will be a fresh sequence of the same type as `seq`.
  Example:
    (take-while #&#39;evenp &#39;(2 4 5 6 7 8))
    ; =&amp;gt; (2 4)
    (take-while #&#39;evenp #(1))
    ; =&amp;gt; #()
  &amp;quot;
  (ctypecase seq
    (list (take-while-list predicate seq))
    (sequence (take-while-seq predicate seq))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun drop-list (n list)
  (copy-list (nthcdr n list)))

(defun drop-seq (n seq)
  (subseq seq (min n (length seq))))

(defun drop (n seq)
  &amp;quot;Return a fresh copy of the `seq` without the first `n` elements.
  The result will be of the same type as `seq`.
  If `seq` is shorter than `n` an empty sequence will be returned.
  Example:
    (drop 2 &#39;(a b c))
    =&amp;gt; (c)
    (drop 4 #(1))
    =&amp;gt; #()
  From Serapeum.
  &amp;quot;
  (check-type n array-index)
  (ctypecase seq
    (list (drop-list n seq))
    (sequence (drop-seq n seq))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun drop-while-list (predicate list)
  (iterate (for tail :on list)
           (while (funcall predicate (first tail)))
           (finally (return (copy-list tail)))))

(defun drop-while-seq (predicate seq)
  (let ((start (position-if-not predicate seq)))
    (if start
      (subseq seq start)
      (subseq seq 0 0))))

(defun drop-while (predicate seq)
  &amp;quot;Drop elements from `seq` as long as `predicate` remains true.
  The result will be a fresh sequence of the same type as `seq`.
  Example:
    (drop-while #&#39;evenp &#39;(2 4 5 6 7 8))
    ; =&amp;gt; (5 6 7 8)
    (drop-while #&#39;evenp #(2))
    ; =&amp;gt; #(2)
  &amp;quot;
  (ctypecase seq
    (list (drop-while-list predicate seq))
    (sequence (drop-while-seq predicate seq))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun extrema (predicate sequence)
  &amp;quot;Return the smallest and largest elements of `sequence` according to `predicate`.
  `predicate` should be a strict ordering predicate (e.g. `&amp;lt;`).
  Returns the smallest and largest elements in the sequence as two values,
  respectively.
  &amp;quot;
  (iterate (with min = (elt sequence 0))
           (with max = (elt sequence 0))
           (for el :in-whatever sequence)
           (when (funcall predicate el min) (setf min el))
           (when (funcall predicate max el) (setf max el))
           (finally (return (values min max)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun summation (sequence &amp;amp;key key)
  &amp;quot;Return the sum of all elements of `sequence`.
  If `key` is given, it will be called on each element to compute the addend.
  This function&#39;s ugly name was chosen so it wouldn&#39;t clash with iterate&#39;s `sum`
  symbol.  Sorry.
  Examples:
    (sum #(1 2 3))
    ; =&amp;gt; 6
    (sum &#39;(\&amp;quot;1\&amp;quot; \&amp;quot;2\&amp;quot; \&amp;quot;3\&amp;quot;) :key #&#39;parse-integer)
    ; =&amp;gt; 6
    (sum &#39;(\&amp;quot;1\&amp;quot; \&amp;quot;2\&amp;quot; \&amp;quot;3\&amp;quot;) :key #&#39;length)
    ; =&amp;gt; 3
  &amp;quot;
  (if key
    (iterate (for n :in-whatever sequence)
             (sum (funcall key n)))
    (iterate (for n :in-whatever sequence)
             (sum n))))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun product (sequence &amp;amp;key key)
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L2181
  &amp;quot;Return the product of all elements of `sequence`.
  If `key` is given, it will be called on each element to compute the
  multiplicand.
  Examples:
    (product #(1 2 3))
    ; =&amp;gt; 6
    (product &#39;(\&amp;quot;1\&amp;quot; \&amp;quot;2\&amp;quot; \&amp;quot;3\&amp;quot;) :key #&#39;parse-integer)
    ; =&amp;gt; 6
    (product &#39;(\&amp;quot;1\&amp;quot; \&amp;quot;2\&amp;quot; \&amp;quot;3\&amp;quot;) :key #&#39;length)
    ; =&amp;gt; 1
  &amp;quot;
  (if key
    (iterate (for n :in-whatever sequence)
             (multiplying (funcall key n)))
    (iterate (for n :in-whatever sequence)
             (multiplying n))))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;debugging-and-logging&#34;&gt;Debugging and logging&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun pr (&amp;amp;rest args)
  &amp;quot;Print `args` readably, separated by spaces and followed by a newline.
  Returns the first argument, so you can just wrap it around a form without
  interfering with the rest of the program.
  This is what `print` should have been.
  &amp;quot;
  (format t &amp;quot;~{~S~^ ~}~%&amp;quot; args)
  (finish-output)
  (first args))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro prl (&amp;amp;rest args)
  &amp;quot;Print `args` labeled and readably.
  Each argument form will be printed, then evaluated and the result printed.
  One final newline will be printed after everything.
  Returns the last result.
  Examples:
    (let ((i 1)
          (l (list 1 2 3)))
      (prl i (second l)))
    ; =&amp;gt;
    i 1
    (second l) 2
  &amp;quot;
  `(prog1
    (progn ,@(mapcar (lambda (arg) `(pr &#39;,arg ,arg)) args))
    (terpri)
    (finish-output)))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro shut-up (&amp;amp;body body)
  &amp;quot;Run `body` with stdout and stderr redirected to the void.&amp;quot;
  `(let ((*standard-output* (make-broadcast-stream))
         (*error-output* (make-broadcast-stream)))
    ,@body))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro comment (&amp;amp;body body)
  &amp;quot;Do nothing with a bunch of forms.
  Handy for block-commenting multiple expressions.
  &amp;quot;
  (declare (ignore body))
  nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty-print a table.&lt;/p&gt;

&lt;p&gt;Didn&amp;rsquo;t test.&lt;/p&gt;

&lt;p&gt;See also &lt;a href=&#34;https://github.com/vindarel/cl-ansi-term&#34;&gt;https://github.com/vindarel/cl-ansi-term&lt;/a&gt;&lt;/p&gt;

&lt;!-- TODO: test --&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun print-table (rows)
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L2334
  &amp;quot;Print `rows` as a nicely-formatted table.
  Each row should have the same number of colums.
  Columns will be justified properly to fit the longest item in each one.
  Example:
    (print-table &#39;((1 :red something)
                   (2 :green more)))
    =&amp;gt;
    1 | RED   | SOMETHING
    2 | GREEN | MORE
  &amp;quot;
  (when rows
    (iterate
      (with column-sizes =
            (reduce (alexandria:curry #&#39;mapcar #&#39;max)
                    (mapcar (alexandria:curry #&#39;mapcar (compose #&#39;length #&#39;aesthetic-string))
                            rows))) ; lol
      (for row :in rows)
      (format t &amp;quot;~{~vA~^ | ~}~%&amp;quot; (weave column-sizes row))))
  (values))


;; from Quickutil.
(defun ensure-function (function-designator)
    &amp;quot;Returns the function designated by `function-designator`:
if `function-designator` is a function, it is returned, otherwise
it must be a function name and its `fdefinition` is returned.&amp;quot;
    (if (functionp function-designator)
        function-designator
        (fdefinition function-designator)))

;; from Quickutil.
(defun compose (function &amp;amp;rest more-functions)
    &amp;quot;Returns a function composed of `function` and `more-functions` that applies its ;
arguments to to each in turn, starting from the rightmost of `more-functions`,
and then calling the next one with the primary value of the last.&amp;quot;
    (declare (optimize (speed 3) (safety 1) (debug 1)))
    (reduce (lambda (f g)
              (let ((f (ensure-function f))
                    (g (ensure-function g)))
                (lambda (&amp;amp;rest arguments)
                  (declare (dynamic-extent arguments))
                  (funcall f (apply g arguments)))))
            more-functions
            :initial-value function))

(defun make-gensym-list (length &amp;amp;optional (x &amp;quot;G&amp;quot;))
    &amp;quot;Returns a list of `length` gensyms, each generated as if with a call to `make-gensym`,
using the second (optional, defaulting to `\&amp;quot;G\&amp;quot;`) argument.&amp;quot;
    (let ((g (if (typep x &#39;(integer 0)) x (string x))))
      (loop repeat length
            collect (gensym g))))

  (define-compiler-macro compose (function &amp;amp;rest more-functions)
    (labels ((compose-1 (funs)
               (if (cdr funs)
                   `(funcall ,(car funs) ,(compose-1 (cdr funs)))
                   `(apply ,(car funs) arguments))))
      (let* ((args (cons function more-functions))
             (funs (make-gensym-list (length args) &amp;quot;COMPOSE&amp;quot;)))
        `(let ,(loop for f in funs for arg in args
                     collect `(,f (ensure-function ,arg)))
           (declare (optimize (speed 3) (safety 1) (debug 1)))
           (lambda (&amp;amp;rest arguments)
             (declare (dynamic-extent arguments))
             ,(compose-1 funs))))))


;; from Quickutil.
(defun weave (&amp;amp;rest lists)
    &amp;quot;Return a list whose elements alternate between each of the lists
`lists`. Weaving stops when any of the lists has been exhausted.&amp;quot;
    (apply #&#39;mapcan #&#39;list lists))

(defun aesthetic-string (thing)
  &amp;quot;Return the string used to represent `thing` when printing aesthetically.&amp;quot;
  (format nil &amp;quot;~A&amp;quot; thing))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty print a hash-table:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun print-hash-table (hash-table &amp;amp;optional (stream t))
  &amp;quot;Print a pretty representation of `hash-table` to `stream.`
  Respects `*print-length*` when printing the elements.
  &amp;quot;
  (let* ((keys (alexandria:hash-table-keys hash-table))
         (vals (alexandria:hash-table-values hash-table))
         (count (hash-table-count hash-table))
         (key-width (-&amp;lt;&amp;gt; keys
                      (mapcar (alexandria:compose #&#39;length #&#39;prin1-to-string) &amp;lt;&amp;gt;)
                      (reduce #&#39;max &amp;lt;&amp;gt; :initial-value 0)
                      (clamp 0 20 &amp;lt;&amp;gt;))))
    (print-unreadable-object (hash-table stream :type t)
      (princ
        ;; Something shits the bed and output gets jumbled (in SBCL at least) if
        ;; we try to print to `stream` directly in the format statement inside
        ;; `print-unreadable-object`, so instead we can just render to a string
        ;; and `princ` that.
        (format nil &amp;quot;:test ~A :count ~D {~%~{~{  ~vs ~s~}~%~}}&amp;quot;
                (hash-table-test hash-table)
                count
                (loop
                  :with limit = (or *print-length* 40)
                  :for key :in keys
                  :for val :in vals
                  :for i :from 0 :to limit
                  :collect
                  (if (= i limit)
                    (list key-width :too-many-items (list (- count i) :more))
                    (list key-width key val))))
        stream)))
  (terpri stream)
  (values))

(defun pht (hash-table &amp;amp;optional (stream t))
  &amp;quot;Synonym for `print-hash-table` for less typing at the REPL.&amp;quot;
  (print-hash-table hash-table stream))

(defun print-hash-table-concisely (hash-table &amp;amp;optional (stream t))
  &amp;quot;Print a concise representation of `hash-table` to `stream.`
  Should respect `*print-length*` when printing the elements.
  &amp;quot;
  (print-unreadable-object (hash-table stream :type t)
    (prin1 (hash-table-test hash-table))
    (write-char #\space stream)
    (prin1 (hash-table-contents hash-table) stream)))

;; needed:
(defun clamp (from to value)
  &amp;quot;Clamp `value` between `from` and `to`.&amp;quot;
  (let ((max (max from to))
        (min (min from to)))
    (cond
      ((&amp;gt; value max) max)
      ((&amp;lt; value min) min)
      (t value))))

;; see
(defmacro -&amp;lt;&amp;gt; (expr &amp;amp;rest forms)
  &amp;quot;Thread the given forms, with `&amp;lt;&amp;gt;` as a placeholder.&amp;quot;
  ;; I am going to lose my fucking mind if I have to program lisp without
  ;; a threading macro, but I don&#39;t want to add another dep to this library, so
  ;; here we are.
  `(let* ((&amp;lt;&amp;gt; ,expr)
          ,@(mapcar (lambda (form)
                      (if (symbolp form)
                        `(&amp;lt;&amp;gt; (,form &amp;lt;&amp;gt;))
                        `(&amp;lt;&amp;gt; ,form)))
                    forms))
     &amp;lt;&amp;gt;))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the &lt;code&gt;-&amp;lt;&amp;gt;&lt;/code&gt; threading macro, see &lt;a href=&#34;https://github.com/nightfly19/cl-arrows&#34;&gt;cl-arrows&lt;/a&gt; and &lt;a href=&#34;https://github.com/hipeta/arrow-macros&#34;&gt;arrow-macros&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;profiling-with-sbcl&#34;&gt;Profiling (with SBCL)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#+sbcl
(defun dump-profile (filename)
  (with-open-file (*standard-output* filename
                                     :direction :output
                                     :if-exists :supersede)
    (sb-sprof:report :type :graph
                     :sort-by :cumulative-samples
                     :sort-order :ascending)
    (sb-sprof:report :type :flat
                     :min-percent 0.5)))

#+sbcl
(defun start-profiling (&amp;amp;key call-count-packages (mode :cpu))
  &amp;quot;Start profiling performance.  SBCL only.
  `call-count-packages` should be a list of package designators.  Functions in
  these packages will have their call counts recorded via
  `sb-sprof::profile-call-counts`.
  &amp;quot;
  (sb-sprof::reset)
  (-&amp;lt;&amp;gt; call-count-packages
    (mapcar #&#39;mkstr &amp;lt;&amp;gt;)
    (mapcar #&#39;string-upcase &amp;lt;&amp;gt;)
    (mapc #&#39;sb-sprof::profile-call-counts &amp;lt;&amp;gt;))
  (sb-sprof::start-profiling :max-samples 50000
                             :mode mode
                             ; :mode :time
                             :sample-interval 0.01
                             :threads :all))

#+sbcl
(defun stop-profiling (&amp;amp;optional (filename &amp;quot;lisp.prof&amp;quot;))
  &amp;quot;Stop profiling performance and dump a report to `filename`.  SBCL only.&amp;quot;
  (sb-sprof::stop-profiling)
  (dump-profile filename))

#+sbcl
(defmacro profile (&amp;amp;body body)
  &amp;quot;Profile `body` and dump the report to `lisp.prof`.&amp;quot;
  `(progn
     (start-profiling)
     (unwind-protect
         (time (progn ,@body))
       (stop-profiling))))
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Print licences used by a given project and its dependencies</title>
      <link>/blog/print-licences-used-by-a-given-project-and-its-dependencies/</link>
      <pubDate>Mon, 22 Jan 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/print-licences-used-by-a-given-project-and-its-dependencies/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/vindarel/print-licenses/&#34;&gt;print-licenses&lt;/a&gt; is a little utility found in
&lt;a href=&#34;https://github.com/sjl/cl-losh/blob/master/losh.lisp&#34;&gt;Steve Losh&amp;rsquo;s gigantic utilities&lt;/a&gt;
and ported to a stand alone project.&lt;/p&gt;

&lt;p&gt;Example usage:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (print-licenses &#39;fast-io)
  =&amp;gt;
  alexandria           | Public Domain / 0-clause MIT
  babel                | MIT
  cffi                 | MIT
  cffi-grovel          | MIT
  cffi-toolchain       | MIT
  fast-io              | NewBSD
  static-vectors       | MIT
  trivial-features     | MIT
  trivial-gray-streams | MIT
  uiop                 | Unspecified
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It may be available on february, 2018 Quicklisp update (&lt;a href=&#34;https://github.com/quicklisp/quicklisp-projects/issues/1432&#34;&gt;request&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;One potential source of caution (&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/7qca2v/print_licenses_used_by_the_given_project_and_its/&#34;&gt;feedback on reddit&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;what many authors put as the license in their asd file is not the license file that is actually included in the source code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;p&gt;Let&amp;rsquo;s read the source, there are many useful bits. The core of the job is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun print-licenses (quicklisp-project-designator)
  (print-table (sort (license-list quicklisp-project-designator)
                     #&#39;string&amp;lt;
                     :key #&#39;car)))

(defun license-list (quicklisp-project-designator)
  (remove-duplicates
    (mapcar (alexandria:rcurry #&#39;coerce &#39;list)
            (alexandria:flatten (license-tree quicklisp-project-designator)))
    :key #&#39;car :test #&#39;string=))

(defun license-tree (quicklisp-project-designator)
  (let ((sys (ql-dist:dependency-tree quicklisp-project-designator)))
    (assert (not (null sys)) ()
      &amp;quot;Cannot find Quicklisp project for designator ~S&amp;quot;
      quicklisp-project-designator)
    (shut-up
      (ql:quickload quicklisp-project-designator))
    (map-tree
      (lambda (s)
        (vector (slot-value s &#39;ql-dist:name)
                (or (asdf:system-license
                      (asdf:find-system
                        (ql-dist:system-file-name s)))
                    &amp;quot;Unspecified&amp;quot;)))
      sys)))

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and those are the remaining building blocks, with a useful
&lt;code&gt;print-table&lt;/code&gt; function, and three of them taken from
&lt;a href=&#34;http://quickutil.org/&#34;&gt;Quickutil&lt;/a&gt;. See their website and how sjl does
to include them (and only them, to keep lightweight dependencies) in a
project without copy-pasting.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defmacro shut-up (&amp;amp;body body)
  &amp;quot;Run `body` with stdout and stderr redirected to the void.&amp;quot;
  `(let ((*standard-output* (make-broadcast-stream))
         (*error-output* (make-broadcast-stream)))
     ,@body))

;; from Quickutil.
(defun map-tree (function tree)
    &amp;quot;Map `function` to each of the leave of `tree`.&amp;quot;
    (check-type tree cons)
    (labels ((rec (tree)
               (cond
                 ((null tree) nil)
                 ((atom tree) (funcall function tree))
                 ((consp tree)
                  (cons (rec (car tree))
                        (rec (cdr tree)))))))
      (rec tree)))

;; from Quickutil
(defun aesthetic-string (thing)
  &amp;quot;Return the string used to represent `thing` when printing aesthetically.&amp;quot;
  (format nil &amp;quot;~A&amp;quot; thing))

;; from Quickutil
(defun weave (&amp;amp;rest lists)
  &amp;quot;Return a list whose elements alternate between each of the lists
`lists`. Weaving stops when any of the lists has been exhausted.&amp;quot;
  (apply #&#39;mapcan #&#39;list lists))

(defun print-table (rows)
  &amp;quot;Print `rows` as a nicely-formatted table.
  Each row should have the same number of colums.
  Columns will be justified properly to fit the longest item in each one.
  Example:
    (print-table &#39;((1 :red something)
                   (2 :green more)))
    =&amp;gt;
    1 | RED   | SOMETHING
    2 | GREEN | MORE
  &amp;quot;
  (when rows
    (iterate
      (with column-sizes =
            (reduce (curry #&#39;mapcar #&#39;max)
                    (mapcar (curry #&#39;mapcar (compose #&#39;length #&#39;aesthetic-string))
                            rows))) ; lol
      (for row :in rows)
      (format t &amp;quot;~{~vA~^ | ~}~%&amp;quot; (weave column-sizes row))))
  (values))
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Generic, consistent and dotted access of data structures with Access</title>
      <link>/blog/generice-consistent-access-of-data-structures-dotted-path/</link>
      <pubDate>Fri, 12 Jan 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/generice-consistent-access-of-data-structures-dotted-path/</guid>
      <description>

&lt;p&gt;A common frustration for (impatient) beginners is to see &lt;em&gt;different
function names&lt;/em&gt; to access common data structures (alists, plists,
hash-tables) and their &lt;em&gt;inconsistencies&lt;/em&gt; (the order of arguments).&lt;/p&gt;

&lt;p&gt;Now they are well documented in the… Common Lisp Coobook of course:
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/data-structures.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/data-structures.html&lt;/a&gt;, but
still;&lt;/p&gt;

&lt;p&gt;and it is annoying to try things out with a data structure and
&lt;em&gt;refactor&lt;/em&gt; the code to use another one.&lt;/p&gt;

&lt;p&gt;The library &lt;em&gt;&lt;a href=&#34;https://github.com/AccelerationNet/access/&#34;&gt;Access&lt;/a&gt;&lt;/em&gt;
solves those problems, it&amp;rsquo;s always&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(access my-var elt)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(if you&amp;rsquo;re into this, note that &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/cl21.html#generic-functions&#34;&gt;CL21 also does this with a generic and extensible &lt;code&gt;getf&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;edit: also &lt;a href=&#34;https://github.com/vseloved/rutils&#34;&gt;rutils&lt;/a&gt; with &lt;code&gt;generic-elt&lt;/code&gt; or &lt;code&gt;?&lt;/code&gt; in the &lt;code&gt;rutilsx&lt;/code&gt; contrib package.&lt;/p&gt;

&lt;p&gt;Access also solves another usecase.&lt;/p&gt;

&lt;p&gt;Sometimes we deal with &lt;em&gt;nested data structures&lt;/em&gt; (alist inside alist
inside alist, or mixed data structures, happens when working with an
API) and, as in other languages, we&amp;rsquo;d like a shortcut to access a
nested element. In Python, we can use &lt;code&gt;addict&lt;/code&gt; to write
&lt;code&gt;foo.one.2.three&lt;/code&gt; instead of &lt;code&gt;foo[&#39;one&#39;][2][&#39;three&#39;]&lt;/code&gt;, with Access we
have two possibilities, see below.&lt;/p&gt;

&lt;p&gt;Oh, and we can be confident &lt;em&gt;it is a battle-tested library&lt;/em&gt;, since it
is the one that powers &lt;a href=&#34;https://github.com/mmontone/djula/&#34;&gt;Djula&lt;/a&gt;&amp;rsquo;s
template variables interplolation (doc is
&lt;a href=&#34;http://mmontone.github.io/djula/doc/build/html/variables.html&#34;&gt;here&lt;/a&gt;), where we can write&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{{ var.foo }}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;à la Django for the supported data structures, and Djula is in the top 100 of the most downloaded Quicklisp libraries (&lt;a href=&#34;http://blog.quicklisp.org/2018/01/download-stats-for-december-2017.html&#34;&gt;december 2017 stats&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s install it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;access&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;import its symbols in Slime:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(use-package :access)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;generic-and-consistent-access-accross-alists-plists-hash-tables-clos-slots&#34;&gt;Generic and consistent access accross alists, plists, hash-tables, CLOS slots&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s create our test variables first:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-alist &#39;((:foo . &amp;quot;foo&amp;quot;) (:bar . &amp;quot;bar&amp;quot;)))
MY-ALIST
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-plist (list :foo &amp;quot;foo&amp;quot; :bar &amp;quot;bar&amp;quot;))
MY-PLIST
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-hashtable (make-hash-table))
MY-HASHTABLE
(setf (gethash :foo my-hashtable) &amp;quot;foo&amp;quot;)
&amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass obj-test ()
  ((foo :accessor foo :initarg :foo :initform :foo)
   (bar :accessor bar :initarg :bar :initform :bar)))
;; #&amp;lt;STANDARD-CLASS OBJ-TEST&amp;gt;
(defparameter my-obj (make-instance &#39;obj-test))
;; MY-OBJ
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, let&amp;rsquo;s access the &lt;code&gt;:foo&lt;/code&gt; slot.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;alists&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(access my-alist :foo)
&amp;quot;foo&amp;quot;
T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;instead of &lt;code&gt;(cdr (assoc :foo my-alist))&lt;/code&gt; (with :foo &lt;em&gt;first&lt;/em&gt; argument) or alexandria&amp;rsquo;s &lt;code&gt;(assoc-value my-alist :foo)&lt;/code&gt; (:foo &lt;em&gt;second&lt;/em&gt; argument).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;plists&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(access my-plist :foo)
&amp;quot;foo&amp;quot;
T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;instead of &lt;code&gt;(getf my-plist :foo)&lt;/code&gt; (unlike alists, with :foo as &lt;em&gt;last&lt;/em&gt; argument).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hash-tables&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(access my-hashtable :foo)
&amp;quot;foo&amp;quot;
T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;instead of &lt;code&gt;(gethash :foo my-hashtable)&lt;/code&gt; (:foo &lt;em&gt;first&lt;/em&gt; argument).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;objects&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(access my-obj :foo) ;; &amp;lt;= accessor, not slot name
;; :FOO
;; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;instead of… it depends. Here we named the accessor &lt;code&gt;foo&lt;/code&gt;, so we would have used simply &lt;code&gt;(foo my-obj)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also note that &lt;code&gt;access&lt;/code&gt; returns two values, the value and a boolean, t
if the slot exists, nil otherwise.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;access&lt;/code&gt; is &lt;code&gt;setf&lt;/code&gt;able:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (access my-alist :foo) &amp;quot;oof&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;with-access&#34;&gt;with-access&lt;/h3&gt;

&lt;p&gt;Below, we can bind temporary variables inside &lt;code&gt;with-access&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-access (foo bar (other-name plist))
             my-obj
           (format t &amp;quot;Got: ~a~a~a~&amp;amp;&amp;quot; foo bar other-name)
           ;; we can change variables
           (setf other-name &amp;quot;hello plist&amp;quot;)
           (format t &amp;quot;other-name: ~a~&amp;amp;&amp;quot; other-name)
           ;; it changed the object too
           (format t &amp;quot;object slot: ~a~&amp;amp;&amp;quot; (plist my-obj)))
Got: FOOBAR(FOO foo BAR bar)
other-name: hello plist
object slot: hello plist
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;nested-access&#34;&gt;Nested access&lt;/h2&gt;

&lt;p&gt;For this example we add a &lt;code&gt;plist&lt;/code&gt; slot to our object, which copies our &lt;code&gt;my-plist&lt;/code&gt; by default.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defclass obj-test ()
  ((foo :accessor foo :initarg :foo :initform :foo)
   (bar :accessor bar :initarg :bar :initform :bar)
   (plist :accessor plist :initarg plist :initform (copy-list MY-PLIST))))
#&amp;lt;STANDARD-CLASS OBJ-TEST&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(as being a CLOS object, &lt;code&gt;my-obj&lt;/code&gt; is automatically updated with the new slot).&lt;/p&gt;

&lt;p&gt;We can access the nested plist element &lt;code&gt;:foo&lt;/code&gt; inside the object in one go with &lt;code&gt;accesses&lt;/code&gt; (plurial):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(accesses MY-OBJ &#39;plist :foo)
;; &amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;instead of &lt;code&gt;(getf (plist my-obj) :foo)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;dotted-access&#34;&gt;Dotted access&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;with-dot&lt;/code&gt; or &lt;code&gt;#D&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can rewrite the previous examples with a dot:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-dot ()
    my-alist.foo)
&amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or again&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-dot ()
    my-obj.foo)
&amp;quot;hello plist&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but even shorter, with the &lt;code&gt;#D&lt;/code&gt; reader macro that we enable with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(enable-dot-syntax)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(also works in Slime/Sly, for what I am not sure if I enabled a special feature)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#Dmy-alist.foo
&amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and so, a &lt;em&gt;nested dotted access&lt;/em&gt; through an object and a plist:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; back to initial case
(setf my-obj (make-instance &#39;obj-test))
;; #&amp;lt;OBJ-TEST {1005AA3B13}&amp;gt;
#Dmy-obj.plist.foo
;; &amp;quot;foo&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will return &lt;code&gt;nil&lt;/code&gt; instead of an error if someone in the middle
doesn&amp;rsquo;t have the requested field.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Usage will tell how it is useful, and
I hope it will be to fellow newcomers.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Structures: lightweight records, a step before classes</title>
      <link>/blog/data-structures-structs/</link>
      <pubDate>Wed, 03 Jan 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/data-structures-structs/</guid>
      <description>

&lt;p&gt;Structures offer a way to store data in named slots. They support
single inheritance.&lt;/p&gt;

&lt;p&gt;Classes provided by the Common Lisp Object System (CLOS) are more flexible however structures may offer better performance (see for example the SBCL manual).&lt;/p&gt;

&lt;p&gt;As usual, this is &lt;em&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/data-structures.html#structures&#34;&gt;best read in the Common Lisp Cookbook&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&#34;structures&#34;&gt;Structures&lt;/h2&gt;

&lt;h3 id=&#34;creation&#34;&gt;Creation&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;defstruct&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct person
   id name age)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At creation slots are optional and default to &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To set a default value:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct person
   id
   (name &amp;quot;john doe&amp;quot;)
   age)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also specify the type after the default value:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct person
  id
  (name &amp;quot;john doe&amp;quot; :type string)
  age)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We create an instance with the generated constructor &lt;code&gt;make-&lt;/code&gt; +
&lt;code&gt;&amp;lt;structure-name&amp;gt;&lt;/code&gt;, so &lt;code&gt;make-person&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *me* (make-person))
*me*
#S(PERSON :ID NIL :NAME &amp;quot;john doe&amp;quot; :AGE NIL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;note that printed representations can be read back by the reader.&lt;/p&gt;

&lt;p&gt;With a bad name type:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *bad-name* (make-person :name 123))
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;Invalid initialization argument:
  :NAME
in call for class #&amp;lt;STRUCTURE-CLASS PERSON&amp;gt;.
   [Condition of type SB-PCL::INITARG-ERROR]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can set the structure&amp;rsquo;s constructor so as to create the structure
without using keyword arguments, which can be more convenient
sometimes. We give it a name and the order of the arguments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct (person (:constructor create-person (id name age)))
     id
     name
     age)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our new constructor is &lt;code&gt;create-person&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(create-person 1 &amp;quot;me&amp;quot; 7)
#S(PERSON :ID 1 :NAME &amp;quot;me&amp;quot; :AGE 7)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, the default &lt;code&gt;make-person&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; work any more:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-person :name &amp;quot;me&amp;quot;)
;; debugger:
obsolete structure error for a structure of type PERSON
[Condition of type SB-PCL::OBSOLETE-STRUCTURE]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;slot-access&#34;&gt;Slot access&lt;/h3&gt;

&lt;p&gt;We access the slots with accessors created by &lt;code&gt;&amp;lt;name-of-the-struct&amp;gt;-&lt;/code&gt; + &lt;code&gt;slot-name&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(person-name *me*)
;; &amp;quot;john doe&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we then also have &lt;code&gt;person-age&lt;/code&gt; and &lt;code&gt;person-id&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;setting&#34;&gt;Setting&lt;/h3&gt;

&lt;p&gt;Slots are &lt;code&gt;setf&lt;/code&gt;-able:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (person-name *me*) &amp;quot;Cookbook author&amp;quot;)
(person-name *me*)
;; &amp;quot;Cookbook author&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;predicate&#34;&gt;Predicate&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(person-p *me*)
T
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;single-inheritance&#34;&gt;Single inheritance&lt;/h3&gt;

&lt;p&gt;With the &lt;code&gt;:include &amp;lt;struct&amp;gt;&lt;/code&gt; argument:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct (female (:include person))
     (gender &amp;quot;female&amp;quot; :type string))
(make-female :name &amp;quot;Lilie&amp;quot;)
;; #S(FEMALE :ID NIL :NAME &amp;quot;Lilie&amp;quot; :AGE NIL :GENDER &amp;quot;female&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;limitations&#34;&gt;Limitations&lt;/h3&gt;

&lt;p&gt;After a change, instances are not updated.&lt;/p&gt;

&lt;p&gt;If we try to add a slot (&lt;code&gt;email&lt;/code&gt; below), we have the choice to lose
all instances, or to continue using the new definition of
&lt;code&gt;person&lt;/code&gt;. But the effects of redefining a structure are undefined by
the standard, so it is best to re-compile and re-run the changed
code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defstruct person
       id
       (name &amp;quot;john doe&amp;quot; :type string)
       age
       email)

attempt to redefine the STRUCTURE-OBJECT class PERSON
incompatibly with the current definition
   [Condition of type SIMPLE-ERROR]

Restarts:
 0: [CONTINUE] Use the new definition of PERSON, invalidating already-loaded code and instances.
 1: [RECKLESSLY-CONTINUE] Use the new definition of PERSON as if it were compatible, allowing old accessors to use new instances and allowing new accessors to use old instances.
 2: [CLOBBER-IT] (deprecated synonym for RECKLESSLY-CONTINUE)
 3: [RETRY] Retry SLIME REPL evaluation request.
 4: [*ABORT] Return to SLIME&#39;s top level.
 5: [ABORT] abort thread (#&amp;lt;THREAD &amp;quot;repl-thread&amp;quot; RUNNING {1002A0FFA3}&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we choose restart &lt;code&gt;0&lt;/code&gt;, to use the new definition, we lose access to &lt;code&gt;*me*&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;*me*
obsolete structure error for a structure of type PERSON
   [Condition of type SB-PCL::OBSOLETE-STRUCTURE]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There is also very little introspection.
Portable Common Lisp does not define ways of finding out defined super/sub-structures nor what slots a structure has.&lt;/p&gt;

&lt;p&gt;The Common Lisp Object System (which came after into the language)
doesn&amp;rsquo;t have such limitations. See the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/clos.html&#34;&gt;CLOS section&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/08_.htm&#34;&gt;structures on the hyperspec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;David B. Lamkins, &lt;a href=&#34;http://www.communitypicks.com/r/lisp/s/17592186045679-successful-lisp-how-to-understand-and-use-common&#34;&gt;&amp;ldquo;Successful Lisp, How to Undertsand and Use Common Lisp&amp;rdquo;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Error and condition handling</title>
      <link>/blog/error-and-condition-handling/</link>
      <pubDate>Tue, 02 Jan 2018 15:51:49 +0100</pubDate>
      
      <guid>/blog/error-and-condition-handling/</guid>
      <description>

&lt;p&gt;Common Lisp has mechanisms for error and condition handling as found
in other languages, and can do more.&lt;/p&gt;

&lt;p&gt;What is a condition ?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just like in languages that support exception handling (Java, C++,
Python, etc.), a condition represents, for the most part, an
“exceptional” situation. However, even more so that those languages,
&lt;em&gt;a condition in Common Lisp can represent a general situation where
some branching in program logic needs to take place&lt;/em&gt;, not
necessarily due to some error condition. Due to the highly
interactive nature of Lisp development (the Lisp image in
conjunction with the REPL), this makes perfect sense in a language
like Lisp rather than say, a language like Java or even Python,
which has a very primitive REPL. In most cases, however, we may not
need (or even allow) the interactivity that this system offers
us. Thankfully, the same system works just as well even in
non-interactive mode.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://z0ltan.wordpress.com/2016/08/06/conditions-and-restarts-in-common-lisp/&#34;&gt;z0ltan&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let&amp;rsquo;s dive into it step by step. More resources are given afterwards.&lt;/p&gt;

&lt;p&gt;Now &lt;em&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/error_handling.html&#34;&gt;best read in the Common Lisp Cookbook&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Credit: our &lt;a href=&#34;https://vindarel.github.io/cl-torrents/tutorial.html&#34;&gt;cl-torrents tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note: you can contribute any fix or addition to the Cookbook or this page via git ;)&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#ignore-all-errors-and-return-nil&#34;&gt;Ignore all errors (and return nil)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#catching-any-condition---handler-case&#34;&gt;Catching any condition - handler-case&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#catching-a-specific-condition&#34;&gt;Catching a specific condition&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#ignoring-the-condition-argument&#34;&gt;Ignoring the condition argument&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#handler-case-vs-handler-bind&#34;&gt;handler-case VS handler-bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#handling-conditions---handler-bind&#34;&gt;Handling conditions - handler-bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-conditions&#34;&gt;Creating conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#signaling-throwing-conditions&#34;&gt;Signaling (throwing) conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#restarts-interactive-choices-in-the-debugger&#34;&gt;Restarts, interactive choices in the debugger&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#defining-restarts&#34;&gt;Defining restarts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#calling-restarts-programmatically&#34;&gt;Calling restarts programmatically&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#using-other-restarts&#34;&gt;Using other restarts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#prompting-the-user-to-enter-a-new-value&#34;&gt;Prompting the user to enter a new value&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hide-and-show-restarts&#34;&gt;Hide and show restarts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#run-some-code-condition-or-not-finally&#34;&gt;Run some code, condition or not (&amp;ldquo;finally&amp;rdquo;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resources&#34;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;ignore-all-errors-and-return-nil&#34;&gt;Ignore all errors (and return nil)&lt;/h2&gt;

&lt;p&gt;Sometimes you know that a function can fail and you just want to
ignore it: use &lt;code&gt;ignore-errors&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ignore-errors
  (/ 3 0))
; in: IGNORE-ERRORS (/ 3 0)
;     (/ 3 0)
;
; caught STYLE-WARNING:
;   Lisp error during constant folding:
;   arithmetic error DIVISION-BY-ZERO signalled
;   Operation was (/ 3 0).
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
NIL
#&amp;lt;DIVISION-BY-ZERO {1008FF5F13}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We get a welcome &lt;code&gt;division-by-zero&lt;/code&gt; warning but the code runs well and
it returns two things: &lt;code&gt;nil&lt;/code&gt; and the condition that was signaled. We
could not choose what to return.&lt;/p&gt;

&lt;p&gt;Rembember that we can &lt;code&gt;inspect&lt;/code&gt; the condition with a right click in Slime.&lt;/p&gt;

&lt;h2 id=&#34;catching-any-condition-handler-case&#34;&gt;Catching any condition - handler-case&lt;/h2&gt;

&lt;!-- we will say &#34;handling&#34; for handler-bind --&gt;

&lt;p&gt;&lt;code&gt;ignore-error&lt;/code&gt; is built from &lt;code&gt;handler-case&lt;/code&gt;. We can write the previous
example by catching the general &lt;code&gt;error&lt;/code&gt; but now we can return whatever
we want:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case (/ 3 0)
  (error (c)
    (format t &amp;quot;We caught a condition.~&amp;amp;&amp;quot;)
    (values 0 c)))
; in: HANDLER-CASE (/ 3 0)
;     (/ 3 0)
;
; caught STYLE-WARNING:
;   Lisp error during constant folding:
;   Condition DIVISION-BY-ZERO was signalled.
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
We caught a condition.
0
#&amp;lt;DIVISION-BY-ZERO {1004846AE3}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We also returned two values, 0 and the signaled condition.&lt;/p&gt;

&lt;p&gt;The general form of &lt;code&gt;handler-case&lt;/code&gt; is&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case (code that errors out)
   (condition-type (the-condition) ;; &amp;lt;-- optional argument
      (code))
   (another-condition (the-condition)
       ...))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can also catch all conditions by matching &lt;code&gt;t&lt;/code&gt;, like in a &lt;code&gt;cond&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case
    (progn
      (format t &amp;quot;This won&#39;t work…~%&amp;quot;)
      (/ 3 0))
  (t (c)
    (format t &amp;quot;Got an exception: ~a~%&amp;quot; c)
    (values 0 c)))
;; …
;; This won&#39;t work…
;; Got an exception: arithmetic error DIVISION-BY-ZERO signalled
;; Operation was (/ 3 0).
;; 0
;; #&amp;lt;DIVISION-BY-ZERO {100608F0F3}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;catching-a-specific-condition&#34;&gt;Catching a specific condition&lt;/h2&gt;

&lt;p&gt;We can specify what condition to handle:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case (/ 3 0)
  (division-by-zero (c)
    (format t &amp;quot;Caught division by zero: ~a~%&amp;quot; c)))
;; …
;; Caught division by zero: arithmetic error DIVISION-BY-ZERO signalled
;; Operation was (/ 3 0).
;; NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This workflow is similar to a try/catch as found in other languages, but we can do more.&lt;/p&gt;

&lt;h3 id=&#34;ignoring-the-condition-argument&#34;&gt;Ignoring the condition argument&lt;/h3&gt;

&lt;p&gt;If you don&amp;rsquo;t access the condition object in your handlers, but you still keep it has an argument for good practice, you&amp;rsquo;ll see this compiler warning often:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;; caught STYLE-WARNING:
;   The variable C is defined but never used.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To remove it, use a &lt;code&gt;declare&lt;/code&gt; call as in:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case (/ 3 0)
  (division-by-zero (c)
   (declare (ignore c))
   (format t &amp;quot;Caught division by zero~%&amp;quot;))) ;; we don&#39;t print &amp;quot;c&amp;quot; here and don&#39;t get the warning.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;handler-case-vs-handler-bind&#34;&gt;handler-case VS handler-bind&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;handler-case&lt;/code&gt; is similar to the &lt;code&gt;try/catch&lt;/code&gt; forms that we find in
other languages.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;handler-bind&lt;/code&gt; (see the next examples), is what to use
when we need absolute control over what happens when a signal is
raised. It allows us to use the debugger and restarts, either
interactively or programmatically.&lt;/p&gt;

&lt;p&gt;If some library doesn&amp;rsquo;t catch all conditions and lets some bubble out
to us, we can see the restarts (established by &lt;code&gt;restart-case&lt;/code&gt;)
anywhere deep in the stack, including restarts established by other
libraries whose this library called.  And &lt;em&gt;we can see the stack
trace&lt;/em&gt;, with every frame that was called and, in some lisps, even see
local variables and such. Once we &lt;code&gt;handler-case&lt;/code&gt;, we &amp;ldquo;forget&amp;rdquo; about
this, everything is unwound. &lt;code&gt;handler-bind&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; rewind the
stack.&lt;/p&gt;

&lt;h2 id=&#34;handling-conditions-handler-bind&#34;&gt;Handling conditions - handler-bind&lt;/h2&gt;

&lt;p&gt;Here we use &lt;code&gt;handler-bind&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its general form is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-bind ((a-condition #&#39;function-to-handle-it)
               (another-one #&#39;another-function))
    (code that can...)
    (...error out))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, our simple example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-bind
             ((division-by-zero #&#39;(lambda (c) (format t &amp;quot;hello condition~&amp;amp;&amp;quot;))))
           (/ 3 0))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This prints some warnings, then it prints our &amp;ldquo;hello&amp;rdquo; &lt;em&gt;and still
enters the debugger&lt;/em&gt;. If we don&amp;rsquo;t want to enter the debugger, we have
to define a restart and invoke it.&lt;/p&gt;

&lt;p&gt;A real example with the
&lt;a href=&#34;https://github.com/mrkkrp/unix-opts&#34;&gt;&lt;code&gt;unix-opts&lt;/code&gt;&lt;/a&gt; library, that
parses command line arguments. It defined some conditions:
&lt;code&gt;unknown-option&lt;/code&gt;, &lt;code&gt;missing-arg&lt;/code&gt; and &lt;code&gt;arg-parser-failed&lt;/code&gt;, and it is up
to use to write what to do in these cases.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-bind ((opts:unknown-option #&#39;unknown-option)
               (opts:missing-arg #&#39;missing-arg)
               (opts:arg-parser-failed #&#39;arg-parser-failed))
  (opts:get-opts))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our &lt;code&gt;unknown-option&lt;/code&gt; function is simple and looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun unknown-option (condition)
  (format t &amp;quot;~s option is unknown.~%&amp;quot; (opts:option condition))
  (opts:describe)
  (exit)) ;; &amp;lt;-- we return to the command line, no debugger.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it takes the condition as parameter, so we can read information from
it if needed. Here we get the name of the erronous option with the
defined reader &lt;code&gt;(opts:option condition)&lt;/code&gt; (see below).&lt;/p&gt;

&lt;h2 id=&#34;creating-conditions&#34;&gt;Creating conditions&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;define-condition&lt;/code&gt;, and we can inherit from &lt;code&gt;error&lt;/code&gt; or &lt;code&gt;simple-error&lt;/code&gt;:&lt;/p&gt;

&lt;!-- todo: differences ? --&gt;

&lt;!-- make-condition ? --&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-condition my-division-by-zero (error) ())
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is a regular class, so we can add information into slots. Here, we
add a custom message:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-condition my-division-by-zero (error)
  ((dividend :initarg :dividend
            :reader dividend)) ;; &amp;lt;= so we&#39;ll get the dividend with (dividend condition), as soon as on the next line.
  ;; the :report is the message into the debugger:
  (:report (lambda (condition stream) (format stream &amp;quot;You were going to divide ~a by zero.~&amp;amp;&amp;quot; (dividend condition)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The general form looks like a regular class definition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-condition my-condition (condition-it-inherits-from)
  ;; list of arguments, can be &amp;quot;()&amp;quot;.
  ((message :initarg :message
            :reader my-condition-message)
   (second ...))
  ;; class arguments
  (:report (lambda (condition stream) (...))) ;; what is printed in the REPL.
  (:documentation &amp;quot;a string&amp;quot;)) ;; good practice ;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now when we throw this condition we must pass it an error message (it
is a required argument), and read it with &lt;code&gt;error-message&lt;/code&gt; (the
&lt;code&gt;:reader&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;What&amp;rsquo;s in &lt;code&gt;:report&lt;/code&gt; will be printed in the REPL.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s try our condition. We define a simple function that checks our
divisor, and signals our condition if it is equal to zero:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun my-division (x y)
    (if (= y 0)
        (error &#39;MY-DIVISION-BY-ZERO :dividend x))
    (/ x y))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When we use it, we enter the debugger:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(my-division 3 0)
;;
;; into the debugger:
;;
You were going to divide 3 by zero.
   [Condition of type MY-DIVISION-BY-ZERO]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME&#39;s top level.
 2: [ABORT] abort thread (#&amp;lt;THREAD &amp;quot;repl-thread&amp;quot; RUNNING {1002957FA3}&amp;gt;)

Backtrace:
  0: (MY-DIVISION 3 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can inspect the backtrace, go to the source (&lt;code&gt;v&lt;/code&gt; in Slime), etc.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Here is how &lt;code&gt;unix-opts&lt;/code&gt; defines its &lt;code&gt;unknown-option&lt;/code&gt; condition:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(define-condition troublesome-option (simple-error)
  ((option
    :initarg :option
    :reader option))
  (:report (lambda (c s) (format s &amp;quot;troublesome option: ~s&amp;quot; (option c))))
  (:documentation &amp;quot;Generalization over conditions that have to do with some
particular option.&amp;quot;))

(define-condition unknown-option (troublesome-option)
  ()
  (:report (lambda (c s) (format s &amp;quot;unknown option: ~s&amp;quot; (option c))))
  (:documentation &amp;quot;This condition is thrown when parser encounters
unknown (not previously defined with `define-opts&#39;) option.&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;signaling-throwing-conditions&#34;&gt;Signaling (throwing) conditions&lt;/h2&gt;

&lt;p&gt;We can use &lt;code&gt;error&lt;/code&gt;, like we did above. Two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(error &amp;quot;some text&amp;quot;)&lt;/code&gt;: signals a condition of type &lt;code&gt;simple-error&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(error &#39;my-error :message &amp;quot;We did this and this and it didn&#39;t work.&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Throwing these conditions will enter the interactive debugger,
where a few options will be presented by default. We can give
more options with &lt;em&gt;restarts&lt;/em&gt;,
and we can prevent from entering the debugger by handling the condition and invoking a restart.&lt;/p&gt;

&lt;p&gt;Simple example from &lt;code&gt;unix-opts&lt;/code&gt;: it adds information into the &lt;code&gt;option&lt;/code&gt; slot:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(error &#39;unknown-option
        :option opt)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;restarts-interactive-choices-in-the-debugger&#34;&gt;Restarts, interactive choices in the debugger&lt;/h2&gt;

&lt;h3 id=&#34;defining-restarts&#34;&gt;Defining restarts&lt;/h3&gt;

&lt;p&gt;Restarts are the choices we get in the debugger, which always has the
&lt;code&gt;RETRY&lt;/code&gt; and &lt;code&gt;ABORT&lt;/code&gt; ones. We can add choices to the top of the list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun division-restarter ()
  (restart-case (/ 3 0)
    (return-zero () 0)
    (divide-by-one () (/ 3 1))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By calling this stupid function we get two new choices at the top of the debugger:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;simple-restarts.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Note: read in lisper.in&amp;rsquo;s blogpost on csv parsing (see Resources) how
this system was used effectively in production.&lt;/p&gt;

&lt;p&gt;But that&amp;rsquo;s not all, by handling restarts we can start over the
operation as if the error didn&amp;rsquo;t occur (as seen in the stack).&lt;/p&gt;

&lt;h3 id=&#34;calling-restarts-programmatically&#34;&gt;Calling restarts programmatically&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;invoke-restart&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun division-and-bind ()
           (handler-bind
               ((error (lambda (c)
                         (format t &amp;quot;Got error: ~a~%&amp;quot; c) ;; error-message
                         (format t &amp;quot;and will divide by 1~&amp;amp;&amp;quot;)
                         (invoke-restart &#39;divide-by-one))))
             (division-restarter)))
;; (DIVISION-AND-BIND)
;; Got error: arithmetic error DIVISION-BY-ZERO signalled
;; and will divide by 1
;; Operation was (/ 3 0).
;; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that we called the form that contains our restarts
(&lt;code&gt;division-restarter&lt;/code&gt;) and not the function that throws the error.&lt;/p&gt;

&lt;h3 id=&#34;using-other-restarts&#34;&gt;Using other restarts&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;find-restart &#39;name-of-restart&lt;/code&gt; will return the most recent bound
restart with the given name, or &lt;code&gt;nil&lt;/code&gt;. We can invoke it with
&lt;code&gt;invoke-restart&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;prompting-the-user-to-enter-a-new-value&#34;&gt;Prompting the user to enter a new value&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s add a restart in our &lt;code&gt;division-restarter&lt;/code&gt; to offer the user to
enter a new dividend, and run the division again.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun division-restarter ()
  (restart-case (/ 3 0)
    (return-nil () nil)
    (divide-by-one () (/ 3 1))
    (choose-another-dividend (new-dividend)
      :report &amp;quot;Please choose another dividend&amp;quot;
      :interactive (lambda ()
                     (format t &amp;quot;Enter a new dividend: &amp;quot;)
                     (list (read))) ;; &amp;lt;-- must return a list.
      (format t &amp;quot;New division: 3/~a = ~a~&amp;amp;&amp;quot; new-dividend (/ 3 new-dividend)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We get prompted in the debugger:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;arithmetic error DIVISION-BY-ZERO signalled
Operation was (/ 3 0).
  [Condition of type DIVISION-BY-ZERO]

Restarts:
 0: [RETURN-NIL] RETURN-NIL
 1: [DIVIDE-BY-ONE] DIVIDE-BY-ONE
 2: [CHOOSE-ANOTHER-DIVIDEND] Please choose another dividend &amp;lt;-- new
 3: [RETRY] Retry SLIME REPL evaluation request.
 4: [*ABORT] Return to SLIME&#39;s top level.
 5: [ABORT] abort thread (#&amp;lt;THREAD &amp;quot;repl-thread&amp;quot; RUNNING {1002A47FA3}&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The new &lt;code&gt;choose-another-dividend&lt;/code&gt; restart takes an argument for the
new dividend, that will be fed by the &lt;code&gt;:interactive&lt;/code&gt; lambda, which
&lt;code&gt;read&lt;/code&gt;s for user input and must return a list.&lt;/p&gt;

&lt;p&gt;We use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(division-restarter)
;;
;; Entered debugger, chose the 2nd restart.
;;
Enter a new dividend: 10  &amp;lt;-- got prompted to enter a new value.
New division: 3/10 = 3/10
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In a real situation we might want to call our &amp;ldquo;restarter&amp;rdquo; recursively,
to get into the debugger again if we enter a bad value.&lt;/p&gt;

&lt;h3 id=&#34;hide-and-show-restarts&#34;&gt;Hide and show restarts&lt;/h3&gt;

&lt;p&gt;Restarts can be hidden. In &lt;code&gt;restart-case&lt;/code&gt;, in addition to &lt;code&gt;:report&lt;/code&gt;
and &lt;code&gt;:interactive&lt;/code&gt;, they also accept a &lt;code&gt;:test&lt;/code&gt; key:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(restart-case
   (return-zero ()
     :test (lambda ()
             (some-test))
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;run-some-code-condition-or-not-finally&#34;&gt;Run some code, condition or not (&amp;ldquo;finally&amp;rdquo;)&lt;/h2&gt;

&lt;p&gt;The &amp;ldquo;finally&amp;rdquo; part of others &lt;code&gt;try/catch/finally&lt;/code&gt; forms is done with &lt;code&gt;unwind-protect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is the construct used in &amp;ldquo;with-&amp;rdquo; macros, like &lt;code&gt;with-open-file&lt;/code&gt;,
which always closes the file after it.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;re now more than ready to write some code and to dive into other resources !&lt;/p&gt;

&lt;h2 id=&#34;resources&#34;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html&#34;&gt;Practical Common Lisp: &amp;ldquo;Beyond Exception Handling: Conditions and Restarts&amp;rdquo;&lt;/a&gt; - the go-to tutorial, more explanations and primitives.&lt;/li&gt;
&lt;li&gt;Common Lisp Recipes, chap. 12, by E. Weitz&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node317.html&#34;&gt;language reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisper.in/restarts#signaling-validation-errors&#34;&gt;lisper.in&lt;/a&gt; - example with parsing a csv file and using restarts with success, &lt;a href=&#34;https://www.reddit.com/r/lisp/comments/7k85sf/a_tutorial_on_conditions_and_restarts/drceozm/&#34;&gt;in a flight travel company&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html&#34;&gt;Condition Handling in the Lisp family of languages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://z0ltan.wordpress.com/2016/08/06/conditions-and-restarts-in-common-lisp/&#34;&gt;z0ltan.wordpress.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/svetlyak40wt/python-cl-conditions&#34;&gt;https://github.com/svetlyak40wt/python-cl-conditions&lt;/a&gt; - implementation of the CL conditions system in Python.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title> Scripting. Parsing command line arguments, building self-contained executables.</title>
      <link>/blog/scripting-parsing-command-line-arguments-executables/</link>
      <pubDate>Tue, 02 Jan 2018 07:51:49 +0100</pubDate>
      
      <guid>/blog/scripting-parsing-command-line-arguments-executables/</guid>
      <description>

&lt;p&gt;Using a program from a REPL is fine and well, but if we want to
distribute our program easily, we&amp;rsquo;ll want to build an executable.&lt;/p&gt;

&lt;p&gt;Lisp implementations differ in their processes, but they all create
&lt;strong&gt;self-contained executables&lt;/strong&gt;, for the architecture they are built on. The
final user doesn&amp;rsquo;t need to install a Lisp implementation, he can run
the software right away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start-up times&lt;/strong&gt; are near to zero, specially with SBCL and CCL.&lt;/p&gt;

&lt;p&gt;Binaries &lt;strong&gt;size&lt;/strong&gt; are large-ish. They include the whole Lisp
including its libraries, the names of all symbols, information about
argument lists to functions, the compiler, the debugger, source code
location information, and more.&lt;/p&gt;

&lt;p&gt;Note that we can similarly build self-contained executables for &lt;strong&gt;web apps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now &lt;em&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/scripting.html&#34;&gt;best read in the Common Lisp Cookbook&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#building-a-self-contained-executable&#34;&gt;Building a self-contained executable&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#with-sbcl&#34;&gt;With SBCL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-asdf-updated&#34;&gt;With ASDF [updated]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#with-buildapp-or-roswell&#34;&gt;With Buildapp or Roswell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#for-web-apps&#34;&gt;For web apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#size-and-startup-times-of-executables-per-implementation&#34;&gt;Size and startup times of executables per implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#parsing-command-line-arguments&#34;&gt;Parsing command line arguments&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#declaring-arguments&#34;&gt;Declaring arguments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#parsing&#34;&gt;Parsing&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#handling-malformed-or-missing-arguments&#34;&gt;Handling malformed or missing arguments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#catching-a-c-c-termination-signal&#34;&gt;Catching a C-c termination signal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#continuous-delivery-of-executables&#34;&gt;Continuous delivery of executables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#credit&#34;&gt;Credit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h1 id=&#34;building-a-self-contained-executable&#34;&gt;Building a self-contained executable&lt;/h1&gt;

&lt;h2 id=&#34;with-sbcl&#34;&gt;With SBCL&lt;/h2&gt;

&lt;p&gt;How to build (self-contained) executables is implementation-specific (see
below Buildapp and Rowsell). With SBCL, as says
&lt;a href=&#34;http://www.sbcl.org/manual/index.html#Function-sb_002dext_003asave_002dlisp_002dand_002ddie&#34;&gt;its documentation&lt;/a&gt;,
it is a matter of:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(sb-ext:save-lisp-and-die #P&amp;quot;path/name-of-executable&amp;quot; :toplevel #&#39;my-app:main-function :executable t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;sb-ext&lt;/code&gt; is an SBCL extension to run external processes.  See other
&lt;a href=&#34;http://www.sbcl.org/manual/index.html#Extensions&#34;&gt;SBCL extensions&lt;/a&gt;
(many of them are made implementation-portable in other libraries).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:executable  t&lt;/code&gt;  tells  to  build  an  executable  instead  of  an
image. We  could build an  image to save  the state of  our current
Lisp image, to come back working with it later. Specially useful if
we made a lot of work that is computing intensive.&lt;/p&gt;

&lt;p&gt;If you try to run this in Slime, you&amp;rsquo;ll get an error about threads running:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cannot save core with multiple threads running.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run the command from a simple SBCL repl.&lt;/p&gt;

&lt;p&gt;I suppose your project has Quicklisp dependencies. You must then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ensure Quicklisp is installed and loaded at Lisp startup (you
completed Quicklisp installation)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;load&lt;/code&gt; the project&amp;rsquo;s .asd&lt;/li&gt;
&lt;li&gt;install dependencies&lt;/li&gt;
&lt;li&gt;build the executable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(load &amp;quot;my-app.asd&amp;quot;)
(ql:quickload :my-app)
(sb-ext:save-lisp-and-die #p&amp;quot;my-app-binary&amp;quot; :toplevel #&#39;my-app:main :executable t)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From the command line, or from a Makefile, use &lt;code&gt;--load&lt;/code&gt; and &lt;code&gt;--eval&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;build:
	sbcl --load my-app.asd \
	     --eval &#39;(ql:quickload :my-app)&#39; \
         --eval &amp;quot;(sb-ext:save-lisp-and-die #p\&amp;quot;my-app\&amp;quot; :toplevel #my-app:main :executable t)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;with-asdf-updated&#34;&gt;With ASDF [updated]&lt;/h2&gt;

&lt;p&gt;Now that we&amp;rsquo;seen the basics, we need a portable method. Since its
version 3.1, ASDF allows to do that. It introduces the &lt;a href=&#34;https://common-lisp.net/project/asdf/asdf.html#Convenience-Functions&#34;&gt;&lt;code&gt;make&lt;/code&gt; command&lt;/a&gt;,
that reads parameters from the .asd. Add this to your .asd declaration:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:build-operation &amp;quot;program-op&amp;quot; ;; leave as is
:build-pathname &amp;quot;&amp;lt;binary-name&amp;gt;&amp;quot;
:entry-point &amp;quot;&amp;lt;my-package:main-function&amp;gt;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and call &lt;code&gt;asdf:make :my-package&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, in a Makefile:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;LISP ?= sbcl

build:
    $(LISP) --load torrents.asd \
    	--eval &#39;(ql:quickload :my-app)&#39; \
		--eval &#39;(asdf:make :my-app)&#39; \
		--eval &#39;(quit)&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;with-buildapp-or-roswell&#34;&gt;With Buildapp or Roswell&lt;/h2&gt;

&lt;p&gt;We might  like a more  shell-friendly way to build  our executable,
and while  we&amp;rsquo;re at it  a portable one, so  we would have  the same
command to work with various implementations.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://www.xach.com/lisp/buildapp/&#34;&gt;Buildapp&lt;/a&gt; is a battle-tested
&amp;ldquo;application for SBCL or CCL that configures and saves an executable
Common Lisp image&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Example usage:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;buildapp --output myapp \
         --asdf-path . \
         --asdf-tree ~/quicklisp/dists \
         --load-system my-app \
         --entry my-app:main
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Many applications use it (for example,
&lt;a href=&#34;https://github.com/dimitri/pgloader&#34;&gt;pgloader&lt;/a&gt;).  It is available on
Debian: &lt;code&gt;apt install buildapp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://roswell.github.io&#34;&gt;Roswell&lt;/a&gt;, an implementation manager and much
more, also has the &lt;code&gt;ros build&lt;/code&gt; command, that should work for more
implementations than Buildapp.&lt;/p&gt;

&lt;p&gt;We can also make our app installable with Roswell by a &lt;code&gt;ros install
my-app&lt;/code&gt;. See its documentation&lt;/p&gt;

&lt;h2 id=&#34;for-web-apps&#34;&gt;For web apps&lt;/h2&gt;

&lt;p&gt;We can similarly build a self-contained executable for our web-app. It
would thus contain a web server and would be able to run on the
command line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./my-web-app
Hunchentoot server is started.
Listening on localhost:9003.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that this runs the production webserver, not a development one,
so we can run the binary on our VPS right away and access the app from
outside.&lt;/p&gt;

&lt;p&gt;We have one thing to take care of, it is to find and put the thread of
the running web server on the foreground. In our &lt;code&gt;main&lt;/code&gt; function, we
can do something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun main ()
  (start-app :port 9003) ;; our start-app, for example clack:clack-up
  ;; let the webserver run.
  ;; warning: hardcoded &amp;quot;hunchentoot&amp;quot;.
  (handler-case (bt:join-thread (find-if (lambda (th)
                                            (search &amp;quot;hunchentoot&amp;quot; (bt:thread-name th)))
                                         (bt:all-threads)))
    ;; Catch a user&#39;s C-c
    (#+sbcl sb-sys:interactive-interrupt
      #+ccl  ccl:interrupt-signal-condition
      #+clisp system::simple-interrupt-condition
      #+ecl ext:interactive-interrupt
      #+allegro excl:interrupt-signal
      () (progn
           (format *error-output* &amp;quot;Aborting.~&amp;amp;&amp;quot;)
           (clack:stop *server*)
           (uiop:quit)))
    (error (c) (format t &amp;quot;Woops, an unknown error occured:~&amp;amp;~a~&amp;amp;&amp;quot; c))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We used the &lt;code&gt;bordeaux-threads&lt;/code&gt; library (&lt;code&gt;(ql:quickload
&amp;quot;bordeaux-threads&amp;quot;)&lt;/code&gt;, alias &lt;code&gt;bt&lt;/code&gt;) and &lt;code&gt;uiop&lt;/code&gt;, which is part of ASDF so
already loaded, in order to exit in a portable way (&lt;code&gt;uiop:quit&lt;/code&gt;, with
an optional return code, instead of &lt;code&gt;sb-ext:quit&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&#34;size-and-startup-times-of-executables-per-implementation&#34;&gt;Size and startup times of executables per implementation&lt;/h2&gt;

&lt;p&gt;SBCL isn&amp;rsquo;t the only Lisp implementation.
&lt;a href=&#34;https://gitlab.com/embeddable-common-lisp/ecl/&#34;&gt;ECL&lt;/a&gt;, Embeddable
Common Lisp, transpiles Lisp programs to C.  That creates a smaller
executable.&lt;/p&gt;

&lt;p&gt;According to
&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/46k530/tackling_the_eternal_problem_of_lisp_image_size/&#34;&gt;this reddit source&lt;/a&gt;, ECL produces indeed the smallest executables of all,
an order of magnituted smaller than SBCL, but with a longer startup time.&lt;/p&gt;

&lt;p&gt;CCL&amp;rsquo;s binaries seem to be as fast as SBCL and nearly half the size.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;| program size | implementation |  CPU | startup time |
|--------------+----------------+------+--------------|
|           28 | /bin/true      |  15% |        .0004 |
|         1005 | ecl            | 115% |        .5093 |
|        48151 | sbcl           |  91% |        .0064 |
|        27054 | ccl            |  93% |        .0060 |
|        10162 | clisp          |  96% |        .0170 |
|         4901 | ecl.big        | 113% |        .8223 |
|        70413 | sbcl.big       |  93% |        .0073 |
|        41713 | ccl.big        |  95% |        .0094 |
|        19948 | clisp.big      |  97% |        .0259 |
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- ? We may have another trick  to distribute small executables: to make the fasl files executables. ?--&gt;

&lt;h1 id=&#34;parsing-command-line-arguments&#34;&gt;Parsing command line arguments&lt;/h1&gt;

&lt;p&gt;SBCL stores the command line arguments into &lt;code&gt;sb-ext:*posix-argv*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But that variable name differs from implementations, so we may want a
library to handle the differences for us.&lt;/p&gt;

&lt;p&gt;We also want to parse the arguments.&lt;/p&gt;

&lt;p&gt;A quick look at the
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl#scripting&#34;&gt;awesome-cl#scripting&lt;/a&gt;
list and we&amp;rsquo;ll do that with the
&lt;a href=&#34;https://github.com/mrkkrp/unix-opts&#34;&gt;unix-opts&lt;/a&gt; library.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload &amp;quot;unix-opts&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can call it with its &lt;code&gt;opts&lt;/code&gt; alias (nickname).&lt;/p&gt;

&lt;p&gt;As often work happens in two phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;declaring the options our app accepts, their optional argument, defining their type
(string, integer,…), long and short names, and the required ones,&lt;/li&gt;
&lt;li&gt;parsing them (and handling missing or malformed parameters).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;declaring-arguments&#34;&gt;Declaring arguments&lt;/h2&gt;

&lt;p&gt;We define the arguments with &lt;code&gt;opts:define-opts&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(opts:define-opts
    (:name :help
           :description &amp;quot;print this help text&amp;quot;
           :short #\h
           :long &amp;quot;help&amp;quot;)
    (:name :nb
           :description &amp;quot;here we want a number argument&amp;quot;
           :short #\n
           :long &amp;quot;nb&amp;quot;
           :arg-parser #&#39;parse-integer) ;; &amp;lt;- takes an argument
    (:name :info
           :description &amp;quot;info&amp;quot;
           :short #\i
           :long &amp;quot;info&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here &lt;code&gt;parse-integer&lt;/code&gt; is a built-in CL function.&lt;/p&gt;

&lt;p&gt;Example output on the command line (auto-generated help text):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ my-app -h
my-app. Usage:

Available options:
  -h, --help               print this help text
  -n, --nb ARG             here we want a number argument
  -i, --info               info
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;parsing&#34;&gt;Parsing&lt;/h2&gt;

&lt;p&gt;We parse and get the arguments with &lt;code&gt;opts:get-opts&lt;/code&gt;, which returns two
values: the list of valid options and the remaining free arguments. We
then must use &lt;code&gt;multiple-value-bind&lt;/code&gt; to assign both into variables:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (multiple-value-bind (options free-args)
      ;; There is no error handling yet.
      (opts:get-opts)
      ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can test this by giving a list of strings to &lt;code&gt;get-opts&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(multiple-value-bind (options free-args)
                   (opts:get-opts &#39;(&amp;quot;hello&amp;quot; &amp;quot;-h&amp;quot; &amp;quot;-n&amp;quot; &amp;quot;1&amp;quot;))
                 (format t &amp;quot;Options: ~a~&amp;amp;&amp;quot; options)
                 (format t &amp;quot;free args: ~a~&amp;amp;&amp;quot; free-args))
Options: (HELP T NB-RESULTS 1)
free args: (hello)
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we  put an unknown option,  we get into the  debugger. We&amp;rsquo;ll see
error handling in a moment.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;options&lt;/code&gt; is a
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/data-structures.html#plist&#34;&gt;property list&lt;/a&gt;. We
use &lt;code&gt;getf&lt;/code&gt; and &lt;code&gt;setf&lt;/code&gt; with plists, so that&amp;rsquo;s how we do our
logic. Below we print the help with &lt;code&gt;opts:describe&lt;/code&gt; and then &lt;code&gt;exit&lt;/code&gt;
(in a portable way).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (multiple-value-bind (options free-args)
      (opts:get-opts)

    (if (getf options :help)
        (progn
          (opts:describe
           :prefix &amp;quot;You&#39;re in my-app. Usage:&amp;quot;
           :args &amp;quot;[keywords]&amp;quot;) ;; to replace &amp;quot;ARG&amp;quot; in &amp;quot;--nb ARG&amp;quot;
          (opts:exit))) ;; &amp;lt;= optional return status.
    (if (getf options :nb)
       ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For a full example, see its
&lt;a href=&#34;https://github.com/mrkkrp/unix-opts/blob/master/example/example.lisp&#34;&gt;official example&lt;/a&gt;
and
&lt;a href=&#34;https://vindarel.github.io/cl-torrents/tutorial.html&#34;&gt;cl-torrents&amp;rsquo; tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The  example in  the unix-opts  repository suggests  a macro  to do
slightly better. Now to error handling.&lt;/p&gt;

&lt;h3 id=&#34;handling-malformed-or-missing-arguments&#34;&gt;Handling malformed or missing arguments&lt;/h3&gt;

&lt;p&gt;There are 4 situations that unix-opts doesn&amp;rsquo;t handle, but signals
conditions for us to take care of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for an unknown argument: an &lt;code&gt;unknown-option&lt;/code&gt; condition is signaled&lt;/li&gt;
&lt;li&gt;also &lt;code&gt;missing-arg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arg-parser-failed&lt;/code&gt; when, for example, it expected an integer but got text&lt;/li&gt;
&lt;li&gt;&lt;code&gt;missing-required-option&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we must create simple functions to handle those conditions, and
surround the parsing of the options with an &lt;code&gt;handler-bind&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;  (multiple-value-bind (options free-args)
      (handler-bind ((opts:unknown-option #&#39;unknown-option) ;; the condition / our function
                     (opts:missing-arg #&#39;missing-arg)
                     (opts:arg-parser-failed #&#39;arg-parser-failed)
                     (opts:missing-required-option))
         (opts:get-opts))
    …
    ;; use &amp;quot;options&amp;quot; and &amp;quot;free-args&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we suppose we want one function to handle each case, but it could
be a simple one. They take the condition as argument.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun handle-arg-parser-condition (condition)
  (format t &amp;quot;Problem while parsing option ~s: ~a .~%&amp;quot; (opts:option condition) ;; reader to get the option from the condition.
                                                       condition)
  (opts:describe) ;; print help
  (opts:exit)) ;; portable exit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For more about condition handling, see &lt;a href=&#34;error_handling.html&#34;&gt;error and condition handling&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;catching-a-c-c-termination-signal&#34;&gt;Catching a C-c termination signal&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s build a simple binary, run it, try a &lt;code&gt;C-c&lt;/code&gt; and read the stacktrace:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./my-app
sleep…
^C
debugger invoked on a SB-SYS:INTERACTIVE-INTERRUPT in thread   &amp;lt;== condition name
#&amp;lt;THREAD &amp;quot;main thread&amp;quot; RUNNING {1003156A03}&amp;gt;:
  Interactive interrupt at #x7FFFF6C6C170.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [CONTINUE     ] Return from SB-UNIX:SIGINT.               &amp;lt;== it was a SIGINT indeed
  1: [RETRY-REQUEST] Retry the same request.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The signaled condition is named after our implementation:
&lt;code&gt;sb-sys:interactive-interrupt&lt;/code&gt;. We just have to surround our
application code with a &lt;code&gt;handler-case&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case
    (run-my-app free-args)
  (sb-sys:interactive-interrupt () (progn
                                     (format *error-output* &amp;quot;Abort.~&amp;amp;&amp;quot;)
                                     (opts:exit))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code only for SBCL though. We know about
&lt;a href=&#34;https://github.com/guicho271828/trivial-signal/&#34;&gt;trivial-signal&lt;/a&gt;,
but we were not satisfied with our test yet. So we can use something
like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(handler-case
    (run-my-app free-args)
  (#+sbcl sb-sys:interactive-interrupt
   #+ccl  ccl:interrupt-signal-condition
   #+clisp system::simple-interrupt-condition
   #+ecl ext:interactive-interrupt
   #+allegro excl:interrupt-signal
   ()
   (opts:exit)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;here &lt;code&gt;#+&lt;/code&gt; includes the line at compile time depending on
the  implementation.  There&amp;rsquo;s  also &lt;code&gt;#-&lt;/code&gt;.  What &lt;code&gt;#+&lt;/code&gt; does is to look for
symbols in the &lt;code&gt;*features*&lt;/code&gt; list.  We can also combine symbols with
&lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt; and &lt;code&gt;not&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&#34;continuous-delivery-of-executables&#34;&gt;Continuous delivery of executables&lt;/h1&gt;

&lt;p&gt;We can make a Continuous Integration system (Travis CI, Gitlab CI,…)
build binaries for us at every commit, or at every tag pushed or at
wichever other policy.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&#34;testing.html#continuous-integration&#34;&gt;Continuous Integration&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;credit&#34;&gt;Credit&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://vindarel.github.io/cl-torrents/tutorial.html&#34;&gt;cl-torrents&amp;rsquo; tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lisp-journey.gitlab.io/web-dev/&#34;&gt;lisp-journey/web-dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>cl-torrents, app and (extensive) tutorial: web scraping and building executables</title>
      <link>/blog/cl-torrents-app-and-tutorial-web-scraping-building-binaries/</link>
      <pubDate>Wed, 20 Dec 2017 14:21:20 +0100</pubDate>
      
      <guid>/blog/cl-torrents-app-and-tutorial-web-scraping-building-binaries/</guid>
      <description>&lt;p&gt;Lately we exercised our Lisp skills by writing
&lt;a href=&#34;https://github.com/vindarel/cl-torrents&#34;&gt;cl-torrents&lt;/a&gt;, an app that
&lt;strong&gt;searches for torrents&lt;/strong&gt; on several sources (the Pirate Bay through
piratebay.to, Kickass torrents and torrent.cd), and we wrote an
&lt;a href=&#34;https://vindarel.github.io/cl-torrents/tutorial.html&#34;&gt;extensive tutorial&lt;/a&gt;
in the making (that was actually our primary goal). It comes as a
library to use from the REPL and as a &lt;strong&gt;self-contained executable&lt;/strong&gt;
(download and run, nothing more to install). You&amp;rsquo;ll find the following
topics in the tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to &lt;strong&gt;create and load a new project&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;common pitfalls, basic data structures, useful libraries, where to find documentation,&lt;/li&gt;
&lt;li&gt;(async) &lt;strong&gt;web scraping&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;unit testing, with mocks&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;continuous integration&lt;/strong&gt; and delivery of executables (Gitlab CI, Docker),&lt;/li&gt;
&lt;li&gt;parsing &lt;strong&gt;command line arguments&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;building self-contained executables&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;basics of &lt;strong&gt;error handling&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some topics have been ported to the Cookbook, some not (yet).&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://vindarel.github.io/cl-torrents/img-colored-results.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;The next iteration will be about a self-contained web app.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/vindarel/cl-torrents/master/img-cli.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Continuous Integration and delivery on Gitlab CI, testing locally with Docker</title>
      <link>/blog/continuous-integration-delivering-executables-on-gitlab/</link>
      <pubDate>Fri, 01 Dec 2017 14:21:20 +0100</pubDate>
      
      <guid>/blog/continuous-integration-delivering-executables-on-gitlab/</guid>
      <description>&lt;p&gt;&lt;em&gt;Best read in the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci&#34;&gt;Cookbook&lt;/a&gt; !&lt;/em&gt; also Travis CI, code coverage, testing with Prove.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://docs.gitlab.com/ce/ci/README.html&#34;&gt;Gitlab CI&lt;/a&gt; is part of
Gitlab and is available on &lt;a href=&#34;https://gitlab.com/&#34;&gt;Gitlab.com&lt;/a&gt;, for
public and private repositories. Let&amp;rsquo;s see straight away a simple
&lt;code&gt;.gitlab-ci.yml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image: daewok/lisp-devel

before_script:
  - apt-get update -qy
  - apt-get install -y git-core
  - git clone https://github.com/foo/bar ~/quicklisp/local-projects/

test:
  script:
    - make test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gitlab CI is based on Docker. With &lt;code&gt;image&lt;/code&gt; we tell it to use the
&lt;a href=&#34;https://hub.docker.com/r/daewok/lisp-devel/&#34;&gt;daewok/lisp-devel&lt;/a&gt;
one. It includes SBCL, ECL, CCL and ABCL, and Quicklisp is installed
in the home (&lt;code&gt;/home/lisp/&lt;/code&gt;), so we can &lt;code&gt;quickload&lt;/code&gt; packages right
away. If you&amp;rsquo;re interested it also has a more bare bones option. Gitlab will load the
image, clone our project and put us at the project root with
administrative rights to run the rest of the commands.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;test&lt;/code&gt; is a &amp;ldquo;job&amp;rdquo; we define, &lt;code&gt;script&lt;/code&gt; is a
recognized keywords that takes a list of commands to run.&lt;/p&gt;

&lt;p&gt;Suppose we must install dependencies before running our tests:
&lt;code&gt;before_script&lt;/code&gt; will run before each job. Here we clone a library
where Quicklisp can find it, and for doing so we must install git
(Docker images are usually pretty bare bones).&lt;/p&gt;

&lt;p&gt;We can try locally ourselves. If we already installed &lt;a href=&#34;https://docs.docker.com/&#34;&gt;Docker&lt;/a&gt; and
started its daemon (&lt;code&gt;sudo service docker start&lt;/code&gt;), we can do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;docker run --rm -it -v /path/to/local/code:/usr/local/share/common-lisp/source daewok/lisp-devel:latest bash
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will download the lisp image (±400Mo), mount some local code in
the image where indicated, and drop us in bash. Now we can try a &lt;code&gt;make
test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To show you a more complete example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image: daewok/lisp-devel

stages:
  - test
  - build

before_script:
  - apt-get update -qy
  - apt-get install -y git-core
  - git clone https://github.com/foo/bar ~/quicklisp/local-projects/

test:
  stage: test
  script:
    - make test

build:
  stage: build
  only:
    - tags
  script:
    - make build
  artifacts:
    paths:
      - some-file-name
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we defined two &lt;code&gt;stages&lt;/code&gt; (see
&lt;a href=&#34;https://docs.gitlab.com/ce/ci/environments.html&#34;&gt;environments&lt;/a&gt;),
&amp;ldquo;test&amp;rdquo; and &amp;ldquo;build&amp;rdquo;, defined to run one after another. A &amp;ldquo;build&amp;rdquo; stage
will start only if the &amp;ldquo;test&amp;rdquo; one succeesds.&lt;/p&gt;

&lt;p&gt;&amp;ldquo;build&amp;rdquo; is asked to run &lt;code&gt;only&lt;/code&gt; when a
new tag is pushed, not at every commit. When it succeeds, it will make
the files listed in &lt;code&gt;artifacts&lt;/code&gt;&amp;rsquo;s &lt;code&gt;paths&lt;/code&gt; available for download. We can
download them from Gitlab&amp;rsquo;s Pipelines UI, or with an url. This one will download
the file &amp;ldquo;some-file-name&amp;rdquo; from the latest &amp;ldquo;build&amp;rdquo; job:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://gitlab.com/username/project-name/-/jobs/artifacts/master/raw/some-file-name?job=build
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When the pipelines pass, you will see:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://lispcookbook.github.io/cl-cookbook/assets/img-ci-build.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;You now have a ready to use Gitlab CI.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Installing libraries, dependencies management</title>
      <link>/blog/libraries-dependencies-management/</link>
      <pubDate>Fri, 27 Oct 2017 11:01:31 +0200</pubDate>
      
      <guid>/blog/libraries-dependencies-management/</guid>
      <description>

&lt;p&gt;Common Lisp may have more libraries than you think. See:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://quickdocs.org/&#34;&gt;Quickdocs&lt;/a&gt; - the library documentation hosting for CL.&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome-cl&lt;/a&gt; list, a
curated list of libraries.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://lisp-lang.org/wiki/article/recommended-libraries&#34;&gt;lisp-lang.org&amp;rsquo;s recommended libraries&lt;/a&gt; (from &lt;a href=&#34;http://borretti.me/article/common-lisp-sotu-2015&#34;&gt;State of the CL ecosystem, 2015&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quicklisp is the de-facto package manager, but not the only tool.&lt;/p&gt;

&lt;h2 id=&#34;some-terminology-first&#34;&gt;Some terminology first&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the Common Lisp world, a &lt;strong&gt;package&lt;/strong&gt; is a way of grouping symbols
together and of providing encapsulation. It is similar to a C++
namespace, a Python module or a Java package.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A &lt;strong&gt;system&lt;/strong&gt; is a collection of CL source files bundled with an .asd
file which tells how to compile and load them. There is often a
one-to-one relationship between systems and packages, but this is in
no way mandatory. A system may declare a dependency on other
systems. Systems are managed by &lt;a href=&#34;https://common-lisp.net/project/asdf/asdf.html&#34;&gt;ASDF&lt;/a&gt; (Another System Definition
Facility), which offers functionalities similar to those of make and
ld.so, and has become a de facto standard.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A Common Lisp library or project typically consists of one or
several ASDF systems (and is distributed as one Quicklisp project).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;install-quicklisp&#34;&gt;Install Quicklisp&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://www.quicklisp.org/beta/&#34;&gt;Quicklisp&lt;/a&gt; is more than a package
manager, it is also a central repository (a &lt;em&gt;dist&lt;/em&gt;) that ensures that
all libraries build together. This involves some manual work (like
reporting errors to package authors), so this is why Quicklisp
releases its dist updates once a month (but fear not, we have other
tools).&lt;/p&gt;

&lt;p&gt;It provides its own &lt;em&gt;dist&lt;/em&gt; but it is also possible to build our own.&lt;/p&gt;

&lt;p&gt;To install it, we can either:&lt;/p&gt;

&lt;p&gt;1- run this command, anywhere:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -O https://beta.quicklisp.org/quicklisp.lisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and enter a Lisp REPL and load this file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sbcl --load quicklisp.lisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;2- install the Debian package:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apt-get install cl-quicklisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and load it, from a REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(load &amp;quot;/usr/share/cl-quicklisp/quicklisp.lisp&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, in both cases, still from the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(quicklisp-quickstart:install)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will create the &lt;code&gt;~/quicklisp/&lt;/code&gt; directory, where Quicklisp will
maintain its state and downloaded projects.&lt;/p&gt;

&lt;p&gt;If you want Quicklisp to always be loaded in your Lisp sessions, run
&lt;code&gt;(ql:add-to-init-file)&lt;/code&gt;: this adds the right stuff to the init file of
your CL implementation. Otherwise, you have to run &lt;code&gt;(load
&amp;quot;~/quicklisp/setup.lisp&amp;quot;)&lt;/code&gt; in every session if you want to use
Quicklisp or any of the libraries installed through it.&lt;/p&gt;

&lt;p&gt;It adds the following in your (for example) &lt;code&gt;~/.sbclrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;#-quicklisp
  (let ((quicklisp-init (merge-pathnames &amp;quot;quicklisp/setup.lisp&amp;quot;
                                         (user-homedir-pathname))))
    (when (probe-file quicklisp-init)
      (load quicklisp-init)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;install-libraries&#34;&gt;Install libraries&lt;/h2&gt;

&lt;p&gt;In the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;package-name&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and voilà. See Quicklisp&amp;rsquo;s documentation for more commands.&lt;/p&gt;

&lt;p&gt;Note also that dozens of Common Lisp libraries are packaged in
Debian. The package names usually begin with the cl- prefix (use
&lt;code&gt;apt-cache search --names-only &amp;quot;^cl-.*&amp;quot;&lt;/code&gt; to list them all).&lt;/p&gt;

&lt;p&gt;For example, in order to use the CL-PPCRE library (for regular
expressions), one should first install the &lt;code&gt;cl-ppcre&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Then, in SBCL and ECL, it can be used with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(require &amp;quot;asdf&amp;quot;)
(require &amp;quot;cl-ppcre&amp;quot;)
(cl-ppcre:regex-replace &amp;quot;fo+&amp;quot; &amp;quot;foo bar&amp;quot; &amp;quot;frob&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See more: &lt;a href=&#34;https://wiki.debian.org/CommonLisp&#34;&gt;https://wiki.debian.org/CommonLisp&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;advanced-dependencies-management&#34;&gt;Advanced dependencies management&lt;/h2&gt;

&lt;p&gt;Quicklisp installs the libraries into &lt;code&gt;~/quicklisp/local-projects/&lt;/code&gt;. A
library installed here is automatically available for every project.&lt;/p&gt;

&lt;h3 id=&#34;providing-our-own-version-of-a-library-cloning-projects&#34;&gt;Providing our own version of a library. Cloning projects.&lt;/h3&gt;

&lt;p&gt;Given the property above, we can clone any library into the
local-projects directory and it will be found by quicklisp and
available right-away:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &amp;quot;package&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And also given the &lt;code&gt;M-.&lt;/code&gt; &amp;ldquo;go to this symbol definition&amp;rdquo; feature in
Slime (and &lt;code&gt;M-,&lt;/code&gt; to go back), it&amp;rsquo;s really easy to not only explore but
start tweaking and extending other libraries.&lt;/p&gt;

&lt;h3 id=&#34;how-to-work-with-local-versions-of-libraries&#34;&gt;How to work with local versions of libraries&lt;/h3&gt;

&lt;p&gt;If we need libraries to be installed locally, for only one project, or
in order to easily ship a list of dependencies with an application, we
can use &lt;a href=&#34;https://github.com/fukamachi/qlot&#34;&gt;Qlot&lt;/a&gt;. This is like
Python&amp;rsquo;s virtual environments.&lt;/p&gt;

&lt;p&gt;Quicklisp also provides
&lt;a href=&#34;https://www.quicklisp.org/beta/bundles.html&#34;&gt;Quicklisp bundles&lt;/a&gt;. They
are self-contained sets of systems that are exported from Quicklisp
and loadable without involving Quicklisp.&lt;/p&gt;

&lt;p&gt;At last, there&amp;rsquo;s
&lt;a href=&#34;https://github.com/quicklisp/quicklisp-controller&#34;&gt;Quicklisp controller&lt;/a&gt;
to help us build &lt;em&gt;dists&lt;/em&gt;. Some projects use this, like CL21.&lt;/p&gt;

&lt;h2 id=&#34;read-more&#34;&gt;Read more&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Source code organization, libraries and packages:  &lt;a href=&#34;https://lispmethods.com/libraries.html&#34;&gt;https://lispmethods.com/libraries.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wiki.debian.org/CommonLisp&#34;&gt;https://wiki.debian.org/CommonLisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CodyReichert/qi&#34;&gt;Qi&lt;/a&gt; - a package manager for Common Lisp&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Lisp software</title>
      <link>/software/</link>
      <pubDate>Thu, 19 Oct 2017 07:51:49 +0100</pubDate>
      
      <guid>/software/</guid>
      <description>

&lt;p&gt;There&amp;rsquo;s a fantastic showcase of succesfull Common Lisp software on
lisp-lang.org: &lt;a href=&#34;http://lisp-lang.org/success/&#34;&gt;http://lisp-lang.org/success/&lt;/a&gt; so go there first.&lt;/p&gt;

&lt;p&gt;However all are not open source and it doesn&amp;rsquo;t list new or not so
awesome but very cool or interesting software. That&amp;rsquo;s what we&amp;rsquo;ll do
here to see that yeah Lisp is used today and to have code bases to
look at.&lt;/p&gt;

&lt;p&gt;If you are looking for CL &lt;em&gt;libraries&lt;/em&gt;, you of course had a look to the
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome CL&lt;/a&gt; list.&lt;/p&gt;

&lt;h2 id=&#34;awesome-lisp-software&#34;&gt;Awesome Lisp software&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dimitri/pgloader&#34;&gt;pgloader&lt;/a&gt; - &lt;strong&gt;re-written from
Python with a 20 to 30x speed gain&lt;/strong&gt; and more O_o -
&lt;a href=&#34;http://tapoueh.org/blog/2014/05/14-pgloader-got-faster.html&#34;&gt;blog post&lt;/a&gt;
By Dimitri Fontaine working at Postgres in 2014. He also maintains
around 50 Debian packages of Lisp libraries for these needs. He gave
a
&lt;a href=&#34;http://tapoueh.org/confs/2014/05/05-ELS-2014&#34;&gt;lightning talk at the 7th European Lisp Symposium&lt;/a&gt;. Uses &lt;a href=&#34;http://marijnhaverbeke.nl/postmodern/&#34;&gt;Postmodern&lt;/a&gt; and &lt;a href=&#34;http://lparallel.org/&#34;&gt;lparallel&lt;/a&gt; for asynchronous IO. Also,&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;the new code base and feature set seems to attract way more users than the previous implementation ever did, despite using a less popular programming language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/dimitri/pgcharts&#34;&gt;pgchart&lt;/a&gt; - a &lt;strong&gt;self-contained web application&lt;/strong&gt; that takes as input an SQL query text and outputs its data as a chart. By the same Dimitri Fontaine.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/cicakhq/potato&#34;&gt;potato&lt;/a&gt; - a &lt;strong&gt;Slack-like conversation platform&lt;/strong&gt;. Many features. CL in the backend, ClojureScript to the frontend. Apache Solr, RabbitMQ, email updates,… Web, Emacs and Android clients. &lt;a href=&#34;https://www.youtube.com/watch?v=bl8jQ2wRh6k&#34;&gt;web coding video&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/turtl/api&#34;&gt;turtl&lt;/a&gt; - a security focused online &lt;strong&gt;note taking app&lt;/strong&gt;. Deployed at scale at &lt;a href=&#34;https://framanotes.org/&#34;&gt;Framanotes&lt;/a&gt;. Backend in CL.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;internet&#34;&gt;Internet&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nEXT-Browser/nEXT&#34;&gt;nEXT browser&lt;/a&gt; - Qt based &lt;strong&gt;web browser&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-torrents&#34;&gt;cl-torrents&lt;/a&gt; - (my) library, cli and readline app to search for torrents on popular trackers, with an extensive tutorial.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;publishing-software&#34;&gt;Publishing software&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kingcons/coleslaw/&#34;&gt;Coleslaw&lt;/a&gt; - a &lt;strong&gt;static site generator&lt;/strong&gt; similar to Jekyll. With nifty features (build on git push,…). Example blog: &lt;a href=&#34;http://40ants.com/&#34;&gt;http://40ants.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shirakumo.github.io/radiance/&#34;&gt;Radiance&lt;/a&gt; - publishing software, between CMS and framework.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shirakumo/reader&#34;&gt;Reader&lt;/a&gt; - a simple blogging platform for Radiance.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shirakumo/purplish&#34;&gt;Purplish&lt;/a&gt; - an imageboard app for Radiance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;editors&#34;&gt;Editors&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/tamamu/darkmatter&#34;&gt;Darkmatter&lt;/a&gt; - Common Lisp &lt;strong&gt;notebook&lt;/strong&gt; (also exists cl-jupyter). Built on Clack.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/cxxxr/lem&#34;&gt;Lem&lt;/a&gt; - an Emacs clone tailored for Common Lisp development, for the terminal or Electron. &lt;a href=&#34;https://www.youtube.com/watch?v=YkSJ3p7Z9H0&#34;&gt;Screencast&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;gui-apps&#34;&gt;GUI apps&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Shinmera/halftone&#34;&gt;Halftone&lt;/a&gt; - a multiplatform
and portable image viewer. Simple app to demo building Qt GUIs with
Qtools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;terminal-apps&#34;&gt;Terminal apps&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;todo: enhance !&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/pierre-lecocq/pml/blob/master/src/parse.lisp&#34;&gt;Pml&lt;/a&gt; - cli tool to parse my nginx logs and print statistics (and &lt;a href=&#34;https://bitbucket.org/mihailp/tankfeeder/src/ccb6025348243bb98cb3ec27810501492313861f/apache/?at=default&#34;&gt;Tankfeeder for apache&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://vintage-digital.com/hefner/software/shuffletron/&#34;&gt;shuffletron&lt;/a&gt; -
a terminal music player. [staling]&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mrkkrp/shtookovina&#34;&gt;shtookovina&lt;/a&gt; - a program to
help learn natural languages, based on audio recording by the
&lt;a href=&#34;http://shtooka.net/&#34;&gt;Shtooka project&lt;/a&gt;, with an advanced readline
interface and fully hackable in Common Lisp. Deprecated since 2015.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Why do we have to wait one month for Quicklisp updates ?</title>
      <link>/blog/why-do-we-have-to-wait-one-month-before-quicklisp-updates/</link>
      <pubDate>Thu, 31 Aug 2017 18:14:37 +0200</pubDate>
      
      <guid>/blog/why-do-we-have-to-wait-one-month-before-quicklisp-updates/</guid>
      <description>&lt;p&gt;If you didn&amp;rsquo;t know that, now you do. Quicklisp releases software
updates once a month (see
&lt;a href=&#34;http://blog.quicklisp.org/&#34;&gt;Quicklisp&amp;rsquo;s blog&lt;/a&gt;). I didn&amp;rsquo;t know why, it
isn&amp;rsquo;t explained on its website, so I asked
(&lt;a href=&#34;https://github.com/quicklisp/quicklisp-client/issues/148&#34;&gt;issue #148&lt;/a&gt;). I
found the discussion very insightful, everybody being constructive,
existing solutions being discussed and architectural choices
explained. But it ended up brutally with one more Common Lisp oddity.&lt;/p&gt;

&lt;p&gt;My first impression was that this fact is annoying, because it already
prevented me a couple of times to use my own library and its most
recent updates into other projects. They would pull the lib from
Quicklisp but wouldn&amp;rsquo;t benefit from its latest features.&lt;/p&gt;

&lt;p&gt;This way of doing was also not the package management model I was most
used to (pip, npm,…), but by wording things differently it makes more
sense to me. As an user says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think it is a very unique to quicklisp, making sure that everything compiles together. I can&amp;rsquo;t think of any other libraries/frameworks system on other languages/platforms that would go as far. Really great work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So &lt;em&gt;Quicklisp is more than a package manager&lt;/em&gt;, it is a &amp;ldquo;dist&amp;rdquo; builder
ensuring everything works together, closer to apt than to pip.&lt;/p&gt;

&lt;p&gt;The situation and shortcomings is well described by axity on
&lt;a href=&#34;https://www.axity.net/blog/article/8&#34;&gt;his blog post&lt;/a&gt; (update: now available on &lt;a href=&#34;https://mfiano.net/posts/2017-08-25-staying-with-common-lisp/&#34;&gt;mfiano.net&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Zach Beane has done an excellent job with Quicklisp, and it is far better than what we previously had available, but still has a few problems. Zach puts a lot of effort into curating a list of compatible software together into the form of a “Quicklisp dist” rolled out approximately every month. While this is great and puts near-zero maintenance on developers, it poses a few problems.&lt;/p&gt;

&lt;p&gt;Firstly, Zach is a single point of failure. Yes, anyone can maintain their very own Quicklisp dist, but it isn&amp;rsquo;t going to see the masses, and the Quicklisp internals are not very well understood by anyone other than Zach.&lt;/p&gt;

&lt;p&gt;Also the fact that the official dists are rolled out so far apart (a month or longer in the software world is an eternity), means developers cannot push hot-fixes or address user-reported bugs in a timely manner, without pushing maintenance onto the users by having them checkout upstream sources.&lt;/p&gt;

&lt;p&gt;Modern languages such as Julia and Racket offer central repositories where a developer can register their software projects, and will be automatically indexed periodically, so that users can continue to install and update software without any maintenance, and still receive updates quickly when needed. Additionally, they push managing version dependencies onto the developer, which I do not believe to be a bad thing. In contrast, Common Lisp libraries are rarely versioned, and all of that maintenance is forced upon the Quicklisp dist curator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also like /u/ruricolist&amp;rsquo;s explanations
(&lt;a href=&#34;https://www.reddit.com/r/lisp/comments/6snw5d/questions_for_2017_common_lisp_experts/dljcuz9/&#34;&gt;on reddit&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quicklisp provides more assurance than you might expect. The criterion for inclusion, and maintenance, of a project in Quicklisp is that the project successfully load in SBCL alongside all the libraries in that Quicklisp distribution, and load without any errors or warnings. SBCL has extensive type inference and can catch and warn about many potential issues at compile time. And because of the pervasive use of macros in CL, successfully loading a library usually exercises a lot of code paths in its dependencies. To a surprising extent, &amp;ldquo;if it loads, it runs.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Qlot isn&amp;rsquo;t something a library would use. You use it to set up the dependencies for an application. My approach (with TBRSS) is this. Obviously, every time I upgrade to a new Quicklisp dist, I run a test suite to make sure everything is working together. On the rare occasion there&amp;rsquo;s a problem, I either pin the offending library to an older version (with Qlot) or I fork it and fix it, again using Qlot to pull from the fork until the fix makes it into the next Quicklisp dist. And of course I also use Qlot for dependencies that are not, for whatever reason, available in Quicklisp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;p&gt;So Quicklisp&amp;rsquo;s author answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The work relying on me is that I build everything in Quicklisp to make sure they build together before making a release. This covers a useful class of bugs. I&amp;rsquo;d love to incorporate more tests in the process to catch release problems that don&amp;rsquo;t manifest at build time.&lt;/p&gt;

&lt;p&gt;I hope to make it easier for people to learn how to make their own dists. Then people will have the opportunity to make new software sets following the policies that are most important to them. I think there&amp;rsquo;s also plenty of room for other package managers for Common Lisp - maybe something styled more like clbuild would suit people who want instant access to updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why a month ?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A month between updates is a compromise between chaos and stability.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t think shorter release cycles are an unqualified good. In my experience, short release cycles can lead to instability and unpredictability, and I chose one month as a balance between getting timely updates and having a reliable, stable base.&lt;/p&gt;

&lt;p&gt;The most labor-intensive part of making releases is monitoring daily failures and reporting bugs to the right people. The daily failure report is automated, but reporting bugs (and following up) can be a slog.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then the discussion began. When voices support more frequent releases,
Zach advertises again
&lt;a href=&#34;https://github.com/quicklisp/quicklisp-controller&#34;&gt;quicklisp-controller&lt;/a&gt;;
I read one (and only one) small but direct criticism towards the
maintainer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;@Hexstream I don&amp;rsquo;t think a fork will be required. I think this is less of an issue with @xach not willing to make changes required by the community and more of lack of manpower that&amp;rsquo;s willing and able to take up the burden of building and maintaining an automated Quicklisp dist/repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A one month update has its supporters, of course:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have benefited multiple times from the 1 month release cycle and the due diligence that Xach and others put in every month. Even if they had a team of 50 I&amp;rsquo;d still vote to keep it as it is now. Making a separate dist is far more sensible if you need extra control over delivery times and it will still play well with quicklisp and your other projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked whether it would be possible to specify a git version, and I had an explanation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Regarding pulling from git in the client, Quicklisp doesn&amp;rsquo;t work like that. I did not want to rely on external processes in order to be portable to all Common Lisp implementations and platforms. This was a real issue in clbuild and asdf-install.&lt;/p&gt;

&lt;p&gt;If you want to update a bugfix of your library, fix it, and wait a month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and the reminder to try &lt;a href=&#34;https://github.com/fukamachi/qlot&#34;&gt;Qlot&lt;/a&gt;,
which allows exactly that (and to set dependencies locally).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Qlot will not help if you are writing a library and want to push fixes to its users quickly. It only helps for end-user application development. It works similar to virtualenv + pip (requirements.txt) from Python&amp;rsquo;s world, for example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Phoe summed up the situation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This thread is turning into a discussion about &amp;ldquo;why X approach is better than Quicklisp approach&amp;rdquo; which leads to a fruitful, but dead point.&lt;/p&gt;

&lt;p&gt;If someone is not satisfied with the way the current Quicklisp dist works and would rather have a more automated solution, then they are free to extend the quicklisp-controller to their liking and implement the required functionality for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating a centralized service that acts as a QL repository and dist manager,&lt;/li&gt;
&lt;li&gt;allowing the authors to upload and/or update their projects on that service,&lt;/li&gt;
&lt;li&gt;setting up a CI test loop on that service for verifying that the packages build,&lt;/li&gt;
&lt;li&gt;automatically updating the service&amp;rsquo;s dists with new releases,&lt;/li&gt;
&lt;li&gt;maintaining all of the above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Until such a person or group of people appears, nothing is going to be be achieved and nothing in Quicklisp is going to change.&lt;/p&gt;

&lt;p&gt;Talk is cheap - @xach has at least built something that works and can act as a foundation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And now, after only 17 messages to the thread, Zach Beane closes the thread:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I can appreciate there are other approaches that have advantages over how Quicklisp works. I hope this thread has helped shed some light on why it works the way it does, and my hopes for the future. I&amp;rsquo;m not against requests for changes, but not all of them can or will be accommodated. I&amp;rsquo;m also fully in favour of people doing their own thing if they have other priorities, experiences, and preferences - I think it would be great if there were even more options for Common Lisp project management.&lt;/p&gt;

&lt;p&gt;Closing this for now - thanks for the discussion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hexstream had just the time to disagree&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generally agree with your last comment, but I just wanted to express my discontent at the premature closing of this thread, it seemed pretty fruitful to me and I don&amp;rsquo;t think it had yet reached a point of serious diminishing returns.&lt;/p&gt;

&lt;p&gt;(Your project, your rules, though.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and this is it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I think, and I&amp;rsquo;m not the only one, that the thread was fruitful.&lt;/p&gt;

&lt;p&gt;Indeed, we had explanations (that don&amp;rsquo;t appear in the doc), we had
presentation of means to the resolution (in no doc), we had the
presentation of how to fix the mentioned problem for library
developers (Qlot, comprehensibly not referenced in Quicklisp doc, and little talked
about over here), we had questions regarding the lack of documentation
that could be tracked from this thread (Zach too said he wanted to
write more doc). And I think the discussion was professional, with no
animosity. So we could have tracked some progress, maybe we would have
received more tips, but more importantly we&amp;rsquo;d have been done with this
question.&lt;/p&gt;

&lt;p&gt;But the thread is closed O_o Preventing people from communicating
means preventing people from learning from each
other, and thus makes the CL world evolving slower. Or people
quitting, or simply be very surprised and not staying here. Indeed,
it&amp;rsquo;s a negative feeling to see that. Why did Zach close the thread ?
Is he bored of this discussion ? He can ignore it. Bored of being
asked that ? It&amp;rsquo;s a recurrent question in reddit and in blogs. But
this issue is the only mention of the subject on Quicklisp&amp;rsquo;s website and
repository. Closing it makes it much less visible.&lt;/p&gt;

&lt;p&gt;Thus it is more likely newcomers will ask again. It&amp;rsquo;s sure newcomers
won&amp;rsquo;t learn why Quicklisp works like it does, which appears in good
light in that issue (and below in reddit). What happened is again a
thing that makes the CL world impenetrable (or with great effort) and
subject to rants. It doesn&amp;rsquo;t need more reasons, seriously.&lt;/p&gt;

&lt;p&gt;I wouldn&amp;rsquo;t bother if this subject was documented, but it is not. The
issue about documenting Quicklisp, which Zach wanted to fix &amp;ldquo;soon&amp;rdquo;,
stalls since 2014. It&amp;rsquo;s still open, at least.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Final links, with a glimpse of light:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.reddit.com/r/Common_Lisp/comments/6x7c85/why_do_we_have_to_wait_one_month_before_quicklisp/&#34;&gt;the reddit thread&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/CodyReichert/qi&#34;&gt;Qi&lt;/a&gt;, a Common Lisp package
manager in the making - more traditional, no surprises - didn&amp;rsquo;t try.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>How to do Functional Programming in Common Lisp ?</title>
      <link>/blog/functional-programming-in-common-lisp/</link>
      <pubDate>Fri, 28 Jul 2017 17:38:24 +0200</pubDate>
      
      <guid>/blog/functional-programming-in-common-lisp/</guid>
      <description>

&lt;p&gt;or &amp;ldquo;Common Lisp is not very functional-programming oriented&amp;rdquo;. What are the options ?&lt;/p&gt;

&lt;p&gt;I mean, &lt;code&gt;map&lt;/code&gt; is uncommon and there is no short words like &lt;code&gt;take&lt;/code&gt; etc
for functional composition. Right ?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;edit&lt;/strong&gt; see those &lt;a href=&#34;/blog/snippets-functional-style-more/&#34;&gt;snippets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;edit january, 2019&lt;/strong&gt;: see this &lt;a href=&#34;https://stackoverflow.com/questions/54375478/can-lisp-be-easily-used-in-an-immutable-functional-manner/54378903#54378903&#34;&gt;SO answer&lt;/a&gt; and the &lt;a href=&#34;https://github.com/smithzvk/modf&#34;&gt;modf&lt;/a&gt; library.&lt;/p&gt;

&lt;h3 id=&#34;map-and-filter&#34;&gt;Map and filter&lt;/h3&gt;

&lt;p&gt;Indeed, there are 8 or so &lt;code&gt;map&lt;/code&gt; functions. The one we&amp;rsquo;re used to is
&lt;code&gt;mapcar&lt;/code&gt;. The simple &lt;code&gt;map&lt;/code&gt; needs a second argument to specify its return
type: &lt;code&gt;(map &#39;list (lambda…&lt;/code&gt;. &amp;ldquo;filter&amp;rdquo; is named &lt;code&gt;remove-if-not&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mapcan&lt;/code&gt; can also be useful. It concatenates the items into one
list. So with &lt;code&gt;mapcar&lt;/code&gt; we get a list of lists with our items, with
&lt;code&gt;mapcan&lt;/code&gt; simply a list of our items.&lt;/p&gt;

&lt;p&gt;=&amp;gt; improved in &lt;a href=&#34;http://cl21.org/&#34;&gt;cl21&lt;/a&gt;. It defines the usual &lt;code&gt;map&lt;/code&gt;
and &lt;code&gt;keep-if&lt;/code&gt; and more functional verbs: &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, &lt;code&gt;take-while&lt;/code&gt;,
&lt;code&gt;drop-while&lt;/code&gt;, &lt;code&gt;butlast&lt;/code&gt;, &lt;code&gt;sum&lt;/code&gt;,… in addition to &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;last&lt;/code&gt;,
&lt;code&gt;find-if[-not]&lt;/code&gt;, &lt;code&gt;remove-if[-not]&lt;/code&gt;, &lt;code&gt;delete[-if[-not]]&lt;/code&gt;, &lt;code&gt;reverse&lt;/code&gt;,
&lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;remove-duplicates&lt;/code&gt;, &lt;code&gt;every&lt;/code&gt;, &lt;code&gt;some&lt;/code&gt;,…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: remember that we still have access to &lt;code&gt;cl&lt;/code&gt; symbols in CL21.&lt;/p&gt;

&lt;h3 id=&#34;functional-composition&#34;&gt;Functional composition&lt;/h3&gt;

&lt;p&gt;Lack of functional composition ? There is the
&lt;a href=&#34;https://github.com/tokenrove/series/wiki&#34;&gt;Series&lt;/a&gt; library since 1989
that seems great, it lets us &lt;em&gt;&amp;ldquo;write our program in a functional style
without any runtime penalty at all !&amp;rdquo;&lt;/em&gt;
[&lt;a href=&#34;http://malisper.me/2016/04/13/loops-in-lisp-part-4-series/&#34;&gt;malisper&lt;/a&gt;
on his blog post]&lt;/p&gt;

&lt;p&gt;But yes again, it has not the modern vocabulary we expect
and it seems abandonware (and its documentation is an old pdf paper
but now hopefully this wiki is better).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;edit 2021&lt;/strong&gt;: &lt;a href=&#34;https://github.com/cbeo/gtwiwtg&#34;&gt;GTWIWTG&lt;/a&gt; is a &amp;ldquo;generators&amp;rdquo; library similar in scope from Series, with modern idioms, but probably not as efficient. BTW, there are now lots of Series example snippets in the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/iteration.html&#34;&gt;Cookbook/iteration&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;CL21 has an operator to compose functions: &lt;a href=&#34;https://github.com/cl21/cl21/wiki/Language-Difference-between-CL21-and-Common-Lisp#function&#34;&gt;https://github.com/cl21/cl21/wiki/Language-Difference-between-CL21-and-Common-Lisp#function&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;threading-macros-pipes&#34;&gt;Threading macros (pipes)&lt;/h3&gt;

&lt;p&gt;We have two packages in Quicklisp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/nightfly19/cl-arrows&#34;&gt;cl-arrows&lt;/a&gt; defines &lt;code&gt;-&amp;gt;&lt;/code&gt;,
&lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; and the generalized ones &lt;code&gt;-&amp;lt;&amp;gt;&lt;/code&gt; and &lt;code&gt;-&amp;lt;&amp;gt;&amp;gt;&lt;/code&gt;. At the time of
writing it has two unanswered PRs to add more, like the
&amp;ldquo;when-guarded&amp;rdquo;-&amp;ldquo;nil shortcuting diamond wand&amp;rdquo; &lt;code&gt;some-&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/hipeta/arrow-macros&#34;&gt;arrow-macros&lt;/a&gt; is a bit more
complete but has more dependencies (it needs a code walker) which
are not portable (failed on ECL, Allegro, ABCL, Clisp). It has the
&lt;code&gt;some-&amp;gt;&lt;/code&gt;, &lt;code&gt;cond-&amp;gt;&lt;/code&gt; and &lt;code&gt;as-&amp;gt;&lt;/code&gt; ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;data-structures&#34;&gt;Data structures&lt;/h3&gt;

&lt;p&gt;We have the nice &lt;a href=&#34;https://github.com/slburson/fset&#34;&gt;FSet&lt;/a&gt;, the functional collection for Common Lisp.&lt;/p&gt;

&lt;h3 id=&#34;anaphoric-macros-for-shorter-lambdas&#34;&gt;Anaphoric macros (for shorter lambdas)&lt;/h3&gt;

&lt;p&gt;I like anaphoric macros but I didn&amp;rsquo;t find one ready to use in a library to write shorter lambdas. The first macro I wrote was directly to mimick elisp&amp;rsquo;s &lt;code&gt;dash.el&lt;/code&gt; excellent library:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-common-lisp&#34;&gt;(defmacro --map (form list)
  `(mapcar (lambda (it) ,form) ,list))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so than we can write&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-common-lisp&#34;&gt;(--map (* it 2) &#39;(2 3))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;instead of &lt;code&gt;(mapcar (lambda (it) (* it 2) &#39;(2 3)))&lt;/code&gt;.
This macro is very simple. It should be in a library, I don&amp;rsquo;t want to copy-paste it in every project of mine. =&amp;gt; in CL21 ? In Anaphora ?&lt;/p&gt;

&lt;p&gt;=&amp;gt; Personnally I&amp;rsquo;m very happy with
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/cl21.html#shorter-lambda&#34;&gt;cl21&amp;rsquo;s short lambdas&lt;/a&gt;
(that were not documented…):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(map ^(foo-bar %) items)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or with &lt;code&gt;(lm (x)…&lt;/code&gt;. Unused arguments will be ignored automatically.&lt;/p&gt;

&lt;p&gt;I also quite like the Arc way of doing, that I found in the
&lt;a href=&#34;https://github.com/malisper/Clamp&#34;&gt;Clamp&lt;/a&gt; project. Arc is another
language and Clamp is more of a POC I guess.&lt;/p&gt;

&lt;p&gt;For shorter lambdas we also have
&lt;a href=&#34;http://quickdocs.org/f-underscore/api&#34;&gt;f-underscore&lt;/a&gt;, that I see used
in the wild. It defines some macros to write shorter lambdas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; is a synonym for lambda&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f0&lt;/code&gt; is a lambda that takes 0 arguments&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f_&lt;/code&gt; takes one, accessible in &lt;code&gt;_&lt;/code&gt; (underscore)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f_n&lt;/code&gt; takes one &lt;code&gt;&amp;amp;rest&lt;/code&gt; argument&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f_%&lt;/code&gt; ignores its rest argument&lt;/li&gt;
&lt;li&gt;&lt;code&gt;m&lt;/code&gt; is a lambda &amp;ldquo;that has a macro-lambda-list instead of an ordinary lambda-list&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might like &lt;a href=&#34;https://github.com/guicho271828/trivia&#34;&gt;Trivia&lt;/a&gt; for &lt;strong&gt;pattern matching&lt;/strong&gt; too.&lt;/p&gt;

&lt;p&gt;Hope this helps !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Data Structures</title>
      <link>/blog/data-structures/</link>
      <pubDate>Thu, 27 Jul 2017 16:48:42 +0200</pubDate>
      
      <guid>/blog/data-structures/</guid>
      <description>

&lt;p&gt;What the heck are alists and plists exactly, how do we manipulate data
structures ? It seems tedious sometimes, are there helpers ?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best read in the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/data-structures.html&#34;&gt;Cookbook&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We hope to give here a clear reference of the common data
structures. To really learn the language, you should take the time to
read other resources. The following ones, which we relied upon,
have many more details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html&#34;&gt;Practical CL&lt;/a&gt;, by Peter Seibel&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://weitz.de/cl-recipes/&#34;&gt;CL Recipes&lt;/a&gt;, by E. Weitz, full of explanations and tips,&lt;/li&gt;
&lt;li&gt;the
&lt;a href=&#34;http://cvberry.com/tech_writings/notes/common_lisp_standard_draft.html&#34;&gt;CL standard&lt;/a&gt;
with a nice TOC, functions reference, extensive descriptions, more
examples and warnings (i.e: everything).&lt;/li&gt;
&lt;li&gt;a &lt;a href=&#34;http://clqr.boundp.org/&#34;&gt;Common Lisp quick reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#building-lists-cons-cells-lists&#34;&gt;Building lists. Cons cells, lists.&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#carcdr-or-firstrest-and-second-to-tenth&#34;&gt;car/cdr or first/rest (and second&amp;hellip; to tenth)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#last-butlast-nbutlast-optional-n&#34;&gt;last, butlast, nbutlast (&amp;amp;optional n)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reverse-nreverse&#34;&gt;reverse, nreverse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#append&#34;&gt;append&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#push-item-place&#34;&gt;push (item, place)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pop&#34;&gt;pop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nthcdr-index-list&#34;&gt;nthcdr (index, list)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#carcdr-and-composites-cadr-caadr---accessing-lists-inside-lists&#34;&gt;car/cdr and composites (cadr, caadr…) - accessing lists inside lists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#destructuring-bind-parameter-list&#34;&gt;destructuring-bind (parameter*, list)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#predicates-null-listp&#34;&gt;Predicates: null, listp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ldiff-tailp-list-make-list-fill-revappend-nreconc-consp-atom&#34;&gt;ldiff, tailp, list*, make-list, fill, revappend, nreconc, consp, atom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sequences&#34;&gt;Sequences&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#predicates-every-some&#34;&gt;Predicates: every, some,…&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#functions&#34;&gt;Functions&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#length-sequence&#34;&gt;length (sequence)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#member-elt-sequence&#34;&gt;member (elt, sequence)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#elt-sequence-index&#34;&gt;elt (sequence, index)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#count-foo-sequence&#34;&gt;count (foo sequence)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#subseq-sequence-start-end&#34;&gt;subseq (sequence start, [end])&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sort-stable-sort-sequence-test--key-function&#34;&gt;sort, stable-sort (sequence, test [, key function])&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#find-position-foo-sequence&#34;&gt;find, position (foo, sequence)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#search-sequence-a-sequence-b&#34;&gt;search (sequence-a, sequence-b)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#substitute-nsubstituteifif-not&#34;&gt;substitute, nsubstitute[if,if-not]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sort-stable-sort-merge&#34;&gt;sort, stable-sort, merge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#replace-sequence-a-sequence-b&#34;&gt;replace (sequence-a, sequence-b)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#remove-delete-foo-sequence&#34;&gt;remove, delete (foo sequence)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mapping-map-mapcar-remove-if-not&#34;&gt;mapping (map, mapcar, remove-if[-not],&amp;hellip;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#flatten-a-list-alexandria&#34;&gt;Flatten a list (Alexandria)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#creating-lists-with-variables&#34;&gt;Creating lists with variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#comparing-lists&#34;&gt;Comparing lists&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#set&#34;&gt;Set&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fset---immutable-data-structure&#34;&gt;Fset - immutable data structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#arrays-and-vectors&#34;&gt;Arrays and vectors&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#create-an-array-one-or-many-dimensions&#34;&gt;Create an array, one or many dimensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#access-aref-array-i-j-&#34;&gt;Access: aref (array i [j …])&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sizes&#34;&gt;Sizes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#vectors&#34;&gt;Vectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#transforming-a-vector-to-a-list&#34;&gt;Transforming a vector to a list.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hash-table&#34;&gt;Hash Table&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#creating-a-hash-table&#34;&gt;Creating a Hash Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#getting-a-value-from-a-hash-table&#34;&gt;Getting a value from a Hash Table&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#getting-a-key-that-does-not-exist-with-a-default-value&#34;&gt;Getting a key that does not exist with a default value&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#getting-all-keys-or-all-values-of-a-hash-table&#34;&gt;Getting all keys or all values of a hash table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#adding-an-element-to-a-hash-table&#34;&gt;Adding an Element to a Hash Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#testing-for-the-presence-of-a-key-in-a-hash-table&#34;&gt;Testing for the Presence of a Key in a Hash Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#deleting-from-a-hash-table&#34;&gt;Deleting from a Hash Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#traversing-a-hash-table&#34;&gt;Traversing a Hash Table&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#traversign-keys-or-values&#34;&gt;Traversign keys or values&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#counting-the-entries-in-a-hash-table&#34;&gt;Counting the Entries in a Hash Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#performance-issues-the-size-of-your-hash-table&#34;&gt;Performance Issues: The Size of your Hash Table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#alist&#34;&gt;Alist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#plist&#34;&gt;Plist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tree&#34;&gt;Tree&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#sycamore---purely-functional-weight-balanced-binary-trees&#34;&gt;Sycamore - purely functional weight-balanced binary trees&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;lists&#34;&gt;Lists&lt;/h2&gt;

&lt;h3 id=&#34;building-lists-cons-cells-lists&#34;&gt;Building lists. Cons cells, lists.&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;A list is also a sequence, so we can use the functions shown below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The list basic element is the cons cell. We build lists by assembling
cons cells.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(cons 1 2)
;; =&amp;gt; (1 . 2) ;; representation with a point, a dotted pair.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[o|o]--- 2
 |
 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the &lt;code&gt;cdr&lt;/code&gt; of the first cell is another cons cell, and if the &lt;code&gt;cdr&lt;/code&gt; of
this last one is &lt;code&gt;nil&lt;/code&gt;, we build a list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(cons 1 (cons 2 nil))
;; =&amp;gt; (1 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[o|o]---[o|/]
 |       |
 1       2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(ascii art by &lt;a href=&#34;https://github.com/cbaggers/draw-cons-tree&#34;&gt;draw-cons-tree&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;See that the representation is not a dotted pair ? The Lisp printer
understands the convention.&lt;/p&gt;

&lt;p&gt;Finally we can simply build a literal list with &lt;code&gt;list&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(list 1 2)
;; =&amp;gt; (1 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or by calling quote:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;&#39;(1 2)
;; =&amp;gt; (1 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which is shorthand notation for the function call &lt;code&gt;(quote (1 2))&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;car-cdr-or-first-rest-and-second-to-tenth&#34;&gt;car/cdr or first/rest (and second&amp;hellip; to tenth)&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(car (cons 1 2)) ;; =&amp;gt; 1
(cdr (cons 1 2)) ;; =&amp;gt; 2
(first (cons 1 2)) ;; =&amp;gt; 1
(first &#39;(1 2 3)) ;; =&amp;gt; 1
(rest &#39;(1 2 3)) ;; =&amp;gt; (2 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can assign &lt;em&gt;any&lt;/em&gt; new value with &lt;code&gt;setf&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;last-butlast-nbutlast-optional-n&#34;&gt;last, butlast, nbutlast (&amp;amp;optional n)&lt;/h3&gt;

&lt;p&gt;return the last cons cell in a list (or the nth last cons cells).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(last &#39;(1 2 3))
;; =&amp;gt; (3)
(car (last &#39;(1 2 3)) )
;; =&amp;gt; 3
(butlast &#39;(1 2 3))
;; =&amp;gt; (1 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;reverse-nreverse&#34;&gt;reverse, nreverse&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;reverse&lt;/code&gt; and &lt;code&gt;nreverse&lt;/code&gt; return a new sequence.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nreverse&lt;/code&gt; is destructive. The N stands for &lt;strong&gt;non-consing&lt;/strong&gt;, meaning
it doesn&amp;rsquo;t need to allocate any new cons cells. It &lt;em&gt;might&lt;/em&gt; (but in
practice, does) reuse and modify the original sequence:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter mylist &#39;(1 2 3))
;; =&amp;gt; (1 2 3)
(reverse mylist)
;; =&amp;gt; (3 2 1)
mylist
;; =&amp;gt; (1 2 3)
(nreverse mylist)
;; =&amp;gt; (3 2 1)
mylist
;; =&amp;gt; (1) in SBCL but implementation dependant.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;append&#34;&gt;append&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;append&lt;/code&gt; takes any number of list arguments and returns a new list
containing the elements of all its arguments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(append (list 1 2) (list 3 4))
;; =&amp;gt; (1 2 3 4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The new list shares some cons cells with the &lt;code&gt;(3 4)&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://gigamonkeys.com/book/figures/after-append.png&#34;&gt;http://gigamonkeys.com/book/figures/after-append.png&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;a href=&#34;cl21.htm&#34;&gt;cl21&lt;/a&gt;&amp;rsquo;s &lt;code&gt;append&lt;/code&gt; is generic (for strings, lists, vectors and
its abstract-sequence).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nconc&lt;/code&gt; is the recycling equivalent.&lt;/p&gt;

&lt;h3 id=&#34;push-item-place&#34;&gt;push (item, place)&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;push&lt;/code&gt; prepends &lt;em&gt;item&lt;/em&gt; to the list that is stored in &lt;em&gt;place&lt;/em&gt;, stores
the resulting list in &lt;em&gt;place&lt;/em&gt;, and returns the list.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter mylist &#39;(1 2 3))
(push 0 mylist)
;; =&amp;gt; (0 1 2 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter x ’(a (b c) d))
;; =&amp;gt; (A (B C) D)
(push 5 (cadr x))
;; =&amp;gt; (5 B C)
x
;; =&amp;gt; (A (5 B C) D)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;push&lt;/code&gt; is equivalent to &lt;code&gt;(setf place (cons item place ))&lt;/code&gt; except that
the subforms of &lt;em&gt;place&lt;/em&gt; are evaluated only once, and &lt;em&gt;item&lt;/em&gt; is evaluated
before &lt;em&gt;place&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There is no built-in function to &lt;strong&gt;add to the end of a list&lt;/strong&gt;. It is a
more costly operation (have to traverse the whole list). So if you
need to do this: either consider using another data structure, either
just &lt;code&gt;reverse&lt;/code&gt; your list when needed.&lt;/p&gt;

&lt;h3 id=&#34;pop&#34;&gt;pop&lt;/h3&gt;

&lt;p&gt;a destructive operation.&lt;/p&gt;

&lt;h3 id=&#34;nthcdr-index-list&#34;&gt;nthcdr (index, list)&lt;/h3&gt;

&lt;p&gt;Use this if &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;second&lt;/code&gt; and the rest up to &lt;code&gt;tenth&lt;/code&gt; are not
enough.&lt;/p&gt;

&lt;h3 id=&#34;car-cdr-and-composites-cadr-caadr-accessing-lists-inside-lists&#34;&gt;car/cdr and composites (cadr, caadr…) - accessing lists inside lists&lt;/h3&gt;

&lt;p&gt;They make sense when applied to lists containing other lists.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(caar (list 1 2 3))                  ==&amp;gt; error
(caar (list (list 1 2) 3))           ==&amp;gt; 1
(cadr (list (list 1 2) (list 3 4)))  ==&amp;gt; (3 4)
(caadr (list (list 1 2) (list 3 4))) ==&amp;gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;destructuring-bind-parameter-list&#34;&gt;destructuring-bind (parameter*, list)&lt;/h3&gt;

&lt;p&gt;It binds the parameter values to the list elements. We can destructure
trees, plists and even provide defaults.&lt;/p&gt;

&lt;p&gt;Simple matching:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(destructuring-bind (x y z) (list 1 2 3)
  (list :x x :y y :z z))
;; =&amp;gt; (:X 1 :Y 2 :Z 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Matching inside sublists:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(destructuring-bind (x (y1 y2) z) (list 1 (list 2 20) 3)
  (list :x x :y1 y1 :y2 y2 :z z))
;; =&amp;gt; (:X 1 :Y1 2 :Y2 20 :Z 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The parameter list can use the usual &lt;code&gt;&amp;amp;optional&lt;/code&gt;, &lt;code&gt;&amp;amp;rest&lt;/code&gt; and &lt;code&gt;&amp;amp;key&lt;/code&gt;
parameters.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(destructuring-bind (x (y1 &amp;amp;optional y2) z) (list 1 (list 2) 3)
  (list :x x :y1 y1 :y2 y2 :z z))
;; =&amp;gt; (:X 1 :Y1 2 :Y2 NIL :Z 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(destructuring-bind (&amp;amp;key x y z) (list :z 1 :y 2 :x 3)
  (list :x x :y y :z z))
;; =&amp;gt; (:X 3 :Y 2 :Z 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;&amp;amp;whole&lt;/code&gt; parameter is bound to the whole list. It must be the
first one and others can follow.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(destructuring-bind (&amp;amp;whole whole-list &amp;amp;key x y z) (list :z 1 :y 2 :x 3)
  (list :x x :y y :z z :whole whole-list))
;; =&amp;gt; (:X 3 :Y 2 :Z 1 :WHOLE-LIST (:Z 1 :Y 2 :X 3))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Destructuring a plist, giving defaults:&lt;/p&gt;

&lt;p&gt;(example from Common Lisp Recipes, by E. Weitz, Apress, 2016)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(destructuring-bind (&amp;amp;key a (b :not-found) c
                     &amp;amp;allow-other-keys)
    ’(:c 23 :d &amp;quot;D&amp;quot; :a #\A :foo :whatever)
  (list a b c))
;; =&amp;gt; (#\A :NOT-FOUND 23)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If this gives you the will to do pattern matching, see
&lt;a href=&#34;pattern_matching.html&#34;&gt;pattern matching&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;predicates-null-listp&#34;&gt;Predicates: null, listp&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;null&lt;/code&gt; is equivalent to &lt;code&gt;not&lt;/code&gt;, but considered better style.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;listp&lt;/code&gt; tests wether an object is a cons cell or nil.&lt;/p&gt;

&lt;p&gt;and sequences&amp;rsquo; predicates.&lt;/p&gt;

&lt;h3 id=&#34;ldiff-tailp-list-make-list-fill-revappend-nreconc-consp-atom&#34;&gt;ldiff, tailp, list*, make-list, fill, revappend, nreconc, consp, atom&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-list 3 :initial-element &amp;quot;ta&amp;quot;)
;; =&amp;gt; (&amp;quot;ta&amp;quot; &amp;quot;ta&amp;quot; &amp;quot;ta&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(make-list 3)
;; =&amp;gt; (NIL NIL NIL)
(fill * &amp;quot;hello&amp;quot;)
;; =&amp;gt; (&amp;quot;hello&amp;quot; &amp;quot;hello&amp;quot; &amp;quot;hello&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;sequences&#34;&gt;Sequences&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;lists&lt;/strong&gt; and &lt;strong&gt;vectors&lt;/strong&gt; (and thus &lt;strong&gt;strings&lt;/strong&gt;) are sequences.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: see also the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/strings.html&#34;&gt;strings&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;Many of the sequence functions take keyword arguments. All keyword
arguments are optional and, if specified, may appear in any order.&lt;/p&gt;

&lt;p&gt;Pay attention to the &lt;code&gt;:test&lt;/code&gt; argument. It defaults to &lt;code&gt;eql&lt;/code&gt; (for
strings, use &lt;code&gt;:equal&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;:key&lt;/code&gt; argument should be passed either nil, or a function of one
argument. This key function is used as a filter through which the
elements of the sequence are seen. For instance, this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find x y :key &#39;car)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is similar to &lt;code&gt;(assoc* x y)&lt;/code&gt;: It searches for an element of the list
whose car equals x, rather than for an element which equals x
itself. If &lt;code&gt;:key&lt;/code&gt; is omitted or nil, the filter is effectively the
identity function.&lt;/p&gt;

&lt;p&gt;Example with an alist (see definition below):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-alist (list (cons &#39;foo &amp;quot;foo&amp;quot;)
                             (cons &#39;bar &amp;quot;bar&amp;quot;)))
;; =&amp;gt; ((FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;))
(find &#39;bar my-alist)
;; =&amp;gt; NIL
(find &#39;bar my-alist :key &#39;car)
;; =&amp;gt; (BAR . &amp;quot;bar&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For more, use a &lt;code&gt;lambda&lt;/code&gt; that takes one parameter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find &#39;bar my-alist :key (lambda (it) (car it)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: and &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/cl21.html#shorter-lambda&#34;&gt;cl21&lt;/a&gt; has short lambdas:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(find &#39;bar my-alist :key ^(car %))
(find &#39;bar my-alist :key (lm (it) (car it)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;predicates-every-some&#34;&gt;Predicates: every, some,…&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;every, notevery (test, sequence)&lt;/code&gt;: return nil or t, respectively, as
soon as one test on any set of the corresponding elements of sequences
returns nil.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter foo &#39;(1 2 3))
(every #&#39;evenp foo)
;; =&amp;gt; NIL
(some #&#39;evenp foo)
;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;with a list of strings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter str &#39;(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot; &amp;quot;team&amp;quot;))
(every #&#39;stringp str)
;; =&amp;gt; T
(some #&#39;(lambda (it) (= 3 (length it))) str)
;; =&amp;gt; T
(some ^(= 3 (length %)) str) ;; in CL21
;; =&amp;gt; T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;some&lt;/code&gt;, &lt;code&gt;notany&lt;/code&gt; &lt;em&gt;(test, sequence)&lt;/em&gt;: return either the value of the test, or nil.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mismatch&lt;/code&gt; &lt;em&gt;(sequence-a, sequence-b)&lt;/em&gt;: Return position in sequence-a where
sequence-a and sequence-b begin to mismatch. Return NIL if they match
entirely. Other parameters: &lt;code&gt;:from-end bool&lt;/code&gt;, &lt;code&gt;:start1&lt;/code&gt;, &lt;code&gt;:start2&lt;/code&gt; and
their &lt;code&gt;:end[1,2]&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;functions&#34;&gt;Functions&lt;/h3&gt;

&lt;p&gt;See also sequence functions defined in
&lt;a href=&#34;https://common-lisp.net/project/alexandria/draft/alexandria.html#Sequences&#34;&gt;Alexandria&lt;/a&gt;:
&lt;code&gt;starts-with&lt;/code&gt;, &lt;code&gt;ends-with&lt;/code&gt;, &lt;code&gt;ends-with-subseq&lt;/code&gt;, &lt;code&gt;length=&lt;/code&gt;, &lt;code&gt;emptyp&lt;/code&gt;,…&lt;/p&gt;

&lt;h4 id=&#34;length-sequence&#34;&gt;length (sequence)&lt;/h4&gt;

&lt;h4 id=&#34;member-elt-sequence&#34;&gt;member (elt, sequence)&lt;/h4&gt;

&lt;h4 id=&#34;elt-sequence-index&#34;&gt;elt (sequence, index)&lt;/h4&gt;

&lt;p&gt;beware, here the sequence comes first.&lt;/p&gt;

&lt;h4 id=&#34;count-foo-sequence&#34;&gt;count (foo sequence)&lt;/h4&gt;

&lt;p&gt;Return the number of elements in sequence that match &lt;em&gt;foo&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Additional paramaters: &lt;code&gt;:from-end&lt;/code&gt;, &lt;code&gt;:start&lt;/code&gt;, &lt;code&gt;:end&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;See also &lt;code&gt;count-if&lt;/code&gt;, &lt;code&gt;count-not&lt;/code&gt; &lt;em&gt;(test-function sequence)&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&#34;subseq-sequence-start-end&#34;&gt;subseq (sequence start, [end])&lt;/h4&gt;

&lt;p&gt;It is &amp;ldquo;setf&amp;rdquo;able, but only works if the new sequence has the same
length of the one to replace.&lt;/p&gt;

&lt;h4 id=&#34;sort-stable-sort-sequence-test-key-function&#34;&gt;sort, stable-sort (sequence, test [, key function])&lt;/h4&gt;

&lt;h4 id=&#34;find-position-foo-sequence&#34;&gt;find, position (foo, sequence)&lt;/h4&gt;

&lt;p&gt;also &lt;code&gt;find-if&lt;/code&gt;, &lt;code&gt;find-if-not&lt;/code&gt;, &lt;code&gt;position-if&lt;/code&gt;, &lt;code&gt;position-if-not&lt;/code&gt; &lt;em&gt;(test
sequence)&lt;/em&gt;. See &lt;code&gt;:key&lt;/code&gt; and &lt;code&gt;:test&lt;/code&gt; parameters.&lt;/p&gt;

&lt;h4 id=&#34;search-sequence-a-sequence-b&#34;&gt;search (sequence-a, sequence-b)&lt;/h4&gt;

&lt;p&gt;Search sequence-b for a subsequence matching sequence-a. Return
position in sequence-b, or NIL. Has the &lt;code&gt;from-end&lt;/code&gt;, &lt;code&gt;end1/2&lt;/code&gt; and others
parameters.&lt;/p&gt;

&lt;h4 id=&#34;substitute-nsubstitute-if-if-not&#34;&gt;substitute, nsubstitute[if,if-not]&lt;/h4&gt;

&lt;h4 id=&#34;sort-stable-sort-merge&#34;&gt;sort, stable-sort, merge&lt;/h4&gt;

&lt;h4 id=&#34;replace-sequence-a-sequence-b&#34;&gt;replace (sequence-a, sequence-b)&lt;/h4&gt;

&lt;p&gt;Replace elements of sequence-a with elements of
sequence-b.&lt;/p&gt;

&lt;h4 id=&#34;remove-delete-foo-sequence&#34;&gt;remove, delete (foo sequence)&lt;/h4&gt;

&lt;p&gt;Make a copy of sequence without elements matching foo. Has
&lt;code&gt;:start/end&lt;/code&gt;, &lt;code&gt;:key&lt;/code&gt; and &lt;code&gt;:count&lt;/code&gt; parameters.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;delete&lt;/code&gt; is the recycling version of &lt;code&gt;remove&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(remove &amp;quot;foo&amp;quot; &#39;(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot; &amp;quot;foo&amp;quot;) :test &#39;equal)
;; =&amp;gt; (&amp;quot;bar&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;see also &lt;code&gt;remove-if[-not]&lt;/code&gt; below.&lt;/p&gt;

&lt;h3 id=&#34;mapping-map-mapcar-remove-if-not&#34;&gt;mapping (map, mapcar, remove-if[-not],&amp;hellip;)&lt;/h3&gt;

&lt;p&gt;If you&amp;rsquo;re used to map and filter in other languages, you probably want
&lt;code&gt;mapcar&lt;/code&gt;. But it only works on lists, so to iterate on vectors (and
produce either a vector or a list, use &lt;code&gt;(map &#39;list function vector)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;mapcar also accepts multiple lists with &lt;code&gt;&amp;amp;rest more-seqs&lt;/code&gt;.  The
mapping stops as soon as the shortest sequence runs out.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: cl21&amp;rsquo;s &lt;code&gt;map&lt;/code&gt; is a generic &lt;code&gt;mapcar&lt;/code&gt; for lists and vectors.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;map&lt;/code&gt; takes the output-type as first argument (&lt;code&gt;&#39;list&lt;/code&gt;, &lt;code&gt;&#39;vector&lt;/code&gt; or
&lt;code&gt;&#39;string&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter foo &#39;(1 2 3))
(map &#39;list (lambda (it) (* 10 it)) foo)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;reduce&lt;/code&gt; &lt;em&gt;(function, sequence)&lt;/em&gt;. Special parameter: &lt;code&gt;:initial-value&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(reduce &#39;- &#39;(1 2 3 4))
;; =&amp;gt; -8
(reduce &#39;- &#39;(1 2 3 4) :initial-value 100)
;; =&amp;gt; 90
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Filter&lt;/strong&gt; is here called &lt;code&gt;remove-if-not&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;flatten-a-list-alexandria&#34;&gt;Flatten a list (Alexandria)&lt;/h3&gt;

&lt;p&gt;With
&lt;a href=&#34;https://common-lisp.net/project/alexandria/draft/alexandria.html&#34;&gt;Alexandria&lt;/a&gt;,
we have the &lt;code&gt;flatten&lt;/code&gt; function.&lt;/p&gt;

&lt;h3 id=&#34;creating-lists-with-variables&#34;&gt;Creating lists with variables&lt;/h3&gt;

&lt;p&gt;That&amp;rsquo;s one use of the &lt;code&gt;backquote&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *var* &amp;quot;bar&amp;quot;)
;; First try:
&#39;(&amp;quot;foo&amp;quot; *var* &amp;quot;baz&amp;quot;) ;; no backquote
;; =&amp;gt; (&amp;quot;foo&amp;quot; *VAR* &amp;quot;baz&amp;quot;) ;; nope
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Second try, with backquote interpolation:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;`(&amp;quot;foo&amp;quot; ,*var* &amp;quot;baz&amp;quot;)     ;; backquote, comma
;; =&amp;gt; (&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot; &amp;quot;baz&amp;quot;) ;; good
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The backquote first warns we&amp;rsquo;ll do interpolation, the comma introduces
the value of the variable.&lt;/p&gt;

&lt;p&gt;If our variable is a list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *var* &#39;(&amp;quot;bar&amp;quot; &amp;quot;baz&amp;quot;))
;; First try:
`(&amp;quot;foo&amp;quot; ,*var*)
;; =&amp;gt; (&amp;quot;foo&amp;quot; (&amp;quot;bar&amp;quot; &amp;quot;baz&amp;quot;)) ;; nested list
`(&amp;quot;foo&amp;quot; ,@*var*)            ;; backquote, comma-@ to
;; =&amp;gt; (&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot; &amp;quot;baz&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;E. Weitz warns that &amp;ldquo;objects generated this way will very likely share
structure (see Recipe 2-7)&amp;ldquo;.&lt;/p&gt;

&lt;h3 id=&#34;comparing-lists&#34;&gt;Comparing lists&lt;/h3&gt;

&lt;p&gt;We can use sets functions.&lt;/p&gt;

&lt;h2 id=&#34;set&#34;&gt;Set&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;intersection&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What elements are both in list-a and list-b ?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter list-a &#39;(0 1 2 3))
(defparameter list-b &#39;(0 2 4))
(intersection list-a list-b)
;; =&amp;gt; (2 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;set-difference&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remove the elements of list-b from list-a:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(set-difference list-a list-b)
;; =&amp;gt; (3 1)
(set-difference list-b list-a)
;; =&amp;gt; (4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;union&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;join the two lists:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(union list-a list-b)
;; =&amp;gt; (3 1 0 2 4) ;; order can be different in your lisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;set-exclusive-or&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remove the elements that are in both lists:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(set-exclusive-or list-a list-b)
;; =&amp;gt; (4 3 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and their recycling &amp;ldquo;n&amp;rdquo; counterpart (&lt;code&gt;nintersection&lt;/code&gt;,…).&lt;/p&gt;

&lt;p&gt;See also functions in
&lt;a href=&#34;https://common-lisp.net/project/alexandria/draft/alexandria.html#Conses&#34;&gt;Alexandria&lt;/a&gt;:
&lt;code&gt;setp&lt;/code&gt;, &lt;code&gt;set-equal&lt;/code&gt;,…&lt;/p&gt;

&lt;h2 id=&#34;fset-immutable-data-structure&#34;&gt;Fset - immutable data structure&lt;/h2&gt;

&lt;p&gt;You may want to have a look at the
&lt;a href=&#34;https://common-lisp.net/project/fset/Site/FSet-Tutorial.html&#34;&gt;FSet&lt;/a&gt;
library (in Quicklisp).&lt;/p&gt;

&lt;h2 id=&#34;arrays-and-vectors&#34;&gt;Arrays and vectors&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Arrays&lt;/strong&gt; have constant-time access characteristics.&lt;/p&gt;

&lt;p&gt;They can be fixed or adjustable. A &lt;em&gt;simple array&lt;/em&gt; is neither displaced
(using &lt;code&gt;:displaced-to&lt;/code&gt;, to point to another array) nor adjustable
(&lt;code&gt;:adjust-array&lt;/code&gt;), nor does it have a fill pointer (&lt;code&gt;fill-pointer&lt;/code&gt;,
that moves when we add or remove elements).&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;vector&lt;/strong&gt; is an array with rank 1 (of one dimension). It is also a
&lt;em&gt;sequence&lt;/em&gt; (see above).&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;simple vector&lt;/em&gt; is a simple array that is also not specialized (it
doesn&amp;rsquo;t use &lt;code&gt;:element-type&lt;/code&gt; to set the types of the elements).&lt;/p&gt;

&lt;h3 id=&#34;create-an-array-one-or-many-dimensions&#34;&gt;Create an array, one or many dimensions&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;make-array&lt;/code&gt; &lt;em&gt;(sizes-list :adjustable bool)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;adjust-array&lt;/code&gt; &lt;em&gt;(array, sizes-list, :element-type, :initial-element)&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&#34;access-aref-array-i-j&#34;&gt;Access: aref (array i [j …])&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;aref&lt;/code&gt; &lt;em&gt;(array i j k …)&lt;/em&gt; or &lt;code&gt;row-major-aref&lt;/code&gt; &lt;em&gt;(array i)&lt;/em&gt; equivalent to
&lt;code&gt;(aref i i i …)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The result is &lt;code&gt;setf&lt;/code&gt;able.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter myarray (make-array &#39;(2 2 2) :initial-element 1))
myarray
;; =&amp;gt; #3A(((1 1) (1 1)) ((1 1) (1 1)))
(aref myarray 0 0 0)
;; =&amp;gt; 1
(setf (aref myarray 0 0 0) 9)
;; =&amp;gt; 9
(row-major-aref myarray 0)
;; =&amp;gt; 9
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;sizes&#34;&gt;Sizes&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;array-total-size&lt;/code&gt; &lt;em&gt;(array)&lt;/em&gt;: how many elements will fit in the array ?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;array-dimensions&lt;/code&gt; &lt;em&gt;(array)&lt;/em&gt;: list containing the length of the array&amp;rsquo;s dimensions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;array-dimension&lt;/code&gt; &lt;em&gt;(array i)&lt;/em&gt;: length of the *i*th dimension.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;array-rank&lt;/code&gt; number of dimensions of the array.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter myarray (make-array &#39;(2 2 2)))
;; =&amp;gt; MYARRAY
myarray
;; =&amp;gt; #3A(((0 0) (0 0)) ((0 0) (0 0)))
(array-rank myarray)
;; =&amp;gt; 3
(array-dimensions myarray)
;; =&amp;gt; (2 2 2)
(array-dimension myarray 0)
;; =&amp;gt; 2
(array-total-size myarray)
;; =&amp;gt; 8
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;vectors&#34;&gt;Vectors&lt;/h3&gt;

&lt;p&gt;Create with &lt;code&gt;vector&lt;/code&gt; or the reader macro &lt;code&gt;#()&lt;/code&gt;. It returns a &lt;em&gt;simple
vector.&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(vector 1 2 3)
;; =&amp;gt; #(1 2 3)
#(1 2 3)
;; =&amp;gt; #(1 2 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;vector-push&lt;/code&gt; &lt;em&gt;(foo vector)&lt;/em&gt;: replace the vector element pointed to by
the fill pointer by foo. Can be destructive.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vector-push-extend&lt;/code&gt; *(foo vector [extension-num])*t&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vector-pop&lt;/code&gt; &lt;em&gt;(vector)&lt;/em&gt;: return the element of vector its fill pointer
points to.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fill-pointer&lt;/code&gt; &lt;em&gt;(vector)&lt;/em&gt;. &lt;code&gt;setf&lt;/code&gt;able.&lt;/p&gt;

&lt;p&gt;and see also the &lt;em&gt;sequence&lt;/em&gt; functions.&lt;/p&gt;

&lt;h3 id=&#34;transforming-a-vector-to-a-list&#34;&gt;Transforming a vector to a list.&lt;/h3&gt;

&lt;p&gt;If you&amp;rsquo;re mapping over it, see the &lt;code&gt;map&lt;/code&gt; function whose first parameter
is the result type.&lt;/p&gt;

&lt;p&gt;Or use &lt;code&gt;(coerce vector &#39;list)&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;hash-table&#34;&gt;Hash Table&lt;/h2&gt;

&lt;p&gt;Hash Tables are a powerful data structure, associating keys with
values in a very efficient way. Hash Tables are often preferred over
association lists whenever performance is an issue, but they introduce
a little overhead that makes assoc lists better if there are only a
few key-value pairs to maintain.&lt;/p&gt;

&lt;p&gt;Alists can be used sometimes differently though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;they can be ordered&lt;/li&gt;
&lt;li&gt;we can push cons cells that have the same key, remove the one in
front and we have a stack&lt;/li&gt;
&lt;li&gt;they have a human-readable printed representation&lt;/li&gt;
&lt;li&gt;they can be easily (de)serialized&lt;/li&gt;
&lt;li&gt;because of RASSOC, keys and values in alists are essentially
interchangeable; whereas in hash tables, keys and values play very
different roles (as usual, see CL Recipes for more).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a name=&#34;create&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;creating-a-hash-table&#34;&gt;Creating a Hash Table&lt;/h3&gt;

&lt;p&gt;Hash Tables are created using the function
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_mk_has.htm&#34;&gt;&lt;code&gt;make-hash-table&lt;/code&gt;&lt;/a&gt;. It
has no required argument. Its most used optional keyword argument is
&lt;code&gt;:test&lt;/code&gt;, specifying the function used to test the equality of keys.&lt;/p&gt;

&lt;p&gt;If we are using the &lt;a href=&#34;http://cl21.org/&#34;&gt;cl21&lt;/a&gt; extension library, we can
create a hash table and add elements in the same time with the new
&lt;code&gt;#H&lt;/code&gt; reader syntax:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter *my-hash* #H(:name &amp;quot;Eitaro Fukamachi&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then we access an element with&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(getf *my-hash* :name)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;get&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;getting-a-value-from-a-hash-table&#34;&gt;Getting a value from a Hash Table&lt;/h3&gt;

&lt;p&gt;The function
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_gethas.htm&#34;&gt;&lt;code&gt;gethash&lt;/code&gt;&lt;/a&gt;
takes two required arguments: a key and a hash table. It returns two
values: the value corresponding to the key in the hash table (or &lt;code&gt;nil&lt;/code&gt;
if not found), and a boolean indicating whether the key was found in
the table. That second value is necessary since &lt;code&gt;nil&lt;/code&gt; is a valid value
in a key-value pair, so getting &lt;code&gt;nil&lt;/code&gt; as first value from &lt;code&gt;gethash&lt;/code&gt;
does not necessarily mean that the key was not found in the table.&lt;/p&gt;

&lt;h4 id=&#34;getting-a-key-that-does-not-exist-with-a-default-value&#34;&gt;Getting a key that does not exist with a default value&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;gethash&lt;/code&gt; has an optional third argument:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(gethash &#39;bar *my-hash* &amp;quot;default-bar&amp;quot;)
;; =&amp;gt; &amp;quot;default-bar&amp;quot;
;;     NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;getting-all-keys-or-all-values-of-a-hash-table&#34;&gt;Getting all keys or all values of a hash table&lt;/h4&gt;

&lt;p&gt;The
&lt;a href=&#34;https://common-lisp.net/project/alexandria/draft/alexandria.html&#34;&gt;Alexandria&lt;/a&gt;
library (in Quicklisp) has the functions &lt;code&gt;hash-table-keys&lt;/code&gt; and
&lt;code&gt;hash-table-values&lt;/code&gt; for that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload :alexandria)
;; […]
(alexandria:hash-table-keys *my-hash*)
;; =&amp;gt; (BAR)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;add&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;adding-an-element-to-a-hash-table&#34;&gt;Adding an Element to a Hash Table&lt;/h3&gt;

&lt;p&gt;If you want to add an element to a hash table, you can use &lt;code&gt;gethash&lt;/code&gt;,
the function to retrieve elements from the hash table, in conjunction
with
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/m_setf_.htm&#34;&gt;&lt;code&gt;setf&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&amp;gt; (setf (gethash &#39;one-entry *my-hash*) &amp;quot;one&amp;quot;)
&amp;quot;one&amp;quot;
CL-USER&amp;gt; (setf (gethash &#39;another-entry *my-hash*) 2/4)
1/2
CL-USER&amp;gt; (gethash &#39;one-entry *my-hash*)
&amp;quot;one&amp;quot;
T
CL-USER&amp;gt; (gethash &#39;another-entry *my-hash*)
1/2
T
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;test&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;testing-for-the-presence-of-a-key-in-a-hash-table&#34;&gt;Testing for the Presence of a Key in a Hash Table&lt;/h3&gt;

&lt;p&gt;The first value returned by &lt;code&gt;gethash&lt;/code&gt; is the object in the hash table
that&amp;rsquo;s associated with the key you provided as an argument to
&lt;code&gt;gethash&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt; if no value exists for this key. This value can act
as a
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_g.htm#generalized_boolean&amp;quot;&amp;gt;generalized
boolean&#34;&gt;generalized boolean&lt;/a&gt; if you want to test for the presence of keys.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&amp;gt; (setf (gethash &#39;one-entry *my-hash*) &amp;quot;one&amp;quot;)
&amp;quot;one&amp;quot;
CL-USER&amp;gt; (if (gethash &#39;one-entry *my-hash*)
           &amp;quot;Key exists&amp;quot;
           &amp;quot;Key does not exist&amp;quot;)
&amp;quot;Key exists&amp;quot;
CL-USER&amp;gt; (if (gethash &#39;another-entry *my-hash*)
           &amp;quot;Key exists&amp;quot;
           &amp;quot;Key does not exist&amp;quot;)
&amp;quot;Key does not exist&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But note that this does &lt;em&gt;not&lt;/em&gt; work if &lt;code&gt;nil&lt;/code&gt; is amongst the values that
you want to store in the hash.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (setf (gethash &#39;another-entry *my-hash*) nil)
NIL
CL-USER&amp;gt; (if (gethash &#39;another-entry *my-hash*)
           &amp;quot;Key exists&amp;quot;
           &amp;quot;Key does not exist&amp;quot;)
&amp;quot;Key does not exist&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case you&amp;rsquo;ll have to check the &lt;em&gt;second&lt;/em&gt; return value of &lt;code&gt;gethash&lt;/code&gt; which will always return &lt;code&gt;nil&lt;/code&gt; if no value is found and T otherwise.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (if (nth-value 1 (gethash &#39;another-entry *my-hash*))
           &amp;quot;Key exists&amp;quot;
           &amp;quot;Key does not exist&amp;quot;)
&amp;quot;Key exists&amp;quot;
CL-USER&amp;gt; (if (nth-value 1 (gethash &#39;no-entry *my-hash*))
           &amp;quot;Key exists&amp;quot;
           &amp;quot;Key does not exist&amp;quot;)
&amp;quot;Key does not exist&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;del&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;deleting-from-a-hash-table&#34;&gt;Deleting from a Hash Table&lt;/h3&gt;

&lt;p&gt;Use
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_remhas.htm&#34;&gt;&lt;code&gt;remhash&lt;/code&gt;&lt;/a&gt;
to delete a hash entry. Both the key and its associated value will be
removed from the hash table. &lt;code&gt;remhash&lt;/code&gt; returns T if there was such an
entry, &lt;code&gt;nil&lt;/code&gt; otherwise.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&amp;gt; (setf (gethash &#39;first-key *my-hash*) &#39;one)
ONE
CL-USER&amp;gt; (gethash &#39;first-key *my-hash*)
ONE
T
CL-USER&amp;gt; (remhash &#39;first-key *my-hash*)
T
CL-USER&amp;gt; (gethash &#39;first-key *my-hash*)
NIL
NIL
CL-USER&amp;gt; (gethash &#39;no-entry *my-hash*)
NIL
NIL
CL-USER&amp;gt; (remhash &#39;no-entry *my-hash*)
NIL
CL-USER&amp;gt; (gethash &#39;no-entry *my-hash*)
NIL
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;traverse&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;traversing-a-hash-table&#34;&gt;Traversing a Hash Table&lt;/h3&gt;

&lt;p&gt;If you want to perform an action on each entry (i.e., each key-value
pair) in a hash table, you have several options:&lt;/p&gt;

&lt;p&gt;You can use
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_maphas.htm&#34;&gt;&lt;code&gt;maphash&lt;/code&gt;&lt;/a&gt;
which iterates over all entries in the hash table. Its first argument
must be a function which accepts &lt;em&gt;two&lt;/em&gt; arguments, the key and the
value of each entry. Note that due to the nature of hash tables you
&lt;em&gt;can&amp;rsquo;t&lt;/em&gt; control the order in which the entries are provided by
&lt;code&gt;maphash&lt;/code&gt; (or other traversing constructs). &lt;code&gt;maphash&lt;/code&gt; always returns
&lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&amp;gt; (setf (gethash &#39;first-key *my-hash*) &#39;one)
ONE
CL-USER&amp;gt; (setf (gethash &#39;second-key *my-hash*) &#39;two)
TWO
CL-USER&amp;gt; (setf (gethash &#39;third-key *my-hash*) nil)
NIL
CL-USER&amp;gt; (setf (gethash nil *my-hash*) &#39;nil-value)
NIL-VALUE
CL-USER&amp;gt; (defun print-hash-entry (key value)
    (format t &amp;quot;The value associated with the key ~S is ~S~%&amp;quot; key value))
PRINT-HASH-ENTRY
CL-USER&amp;gt; (maphash #&#39;print-hash-entry *my-hash*)
The value associated with the key FIRST-KEY is ONE
The value associated with the key SECOND-KEY is TWO
The value associated with the key THIRD-KEY is NIL
The value associated with the key NIL is NIL-VALUE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also use
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/m_w_hash.htm&#34;&gt;&lt;code&gt;with-hash-table-iterator&lt;/code&gt;&lt;/a&gt;,
a macro which turns (via
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/s_flet_.htm&#34;&gt;&lt;code&gt;macrolet&lt;/code&gt;&lt;/a&gt;)
its first argument into an iterator that on each invocation returns
three values per hash table entry - a generalized boolean that&amp;rsquo;s true
if an entry is returned, the key of the entry, and the value of the
entry. If there are no more entries, only one value is returned -
&lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; same hash-table as above
CL-USER&amp;gt; (with-hash-table-iterator (my-iterator *my-hash*)
           (loop
              (multiple-value-bind (entry-p key value)
                  (my-iterator)
                (if entry-p
                    (print-hash-entry key value)
                    (return)))))
The value associated with the key FIRST-KEY is ONE
The value associated with the key SECOND-KEY is TWO
The value associated with the key THIRD-KEY is NIL
The value associated with the key NIL is NIL-VALUE
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note the following caveat from the HyperSpec: &amp;ldquo;It is unspecified what
happens if any of the implicit interior state of an iteration is
returned outside the dynamic extent of the &lt;code&gt;with-hash-table-iterator&lt;/code&gt;
form such as by returning some closure over the invocation form.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;And there&amp;rsquo;s always &lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/06_a.htm&#34;&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; same hash-table as above
CL-USER&amp;gt; (loop for key being the hash-keys of *my-hash*
           do (print key))
FIRST-KEY
SECOND-KEY
THIRD-KEY
NIL
NIL
CL-USER&amp;gt; (loop for key being the hash-keys of *my-hash*
           using (hash-value value)
           do (format t &amp;quot;The value associated with the key ~S is ~S~%&amp;quot; key value))
The value associated with the key FIRST-KEY is ONE
The value associated with the key SECOND-KEY is TWO
The value associated with the key THIRD-KEY is NIL
The value associated with the key NIL is NIL-VALUE
NIL
CL-USER&amp;gt; (loop for value being the hash-values of *my-hash*
           do (print value))
ONE
TWO
NIL
NIL-VALUE
NIL
CL-USER&amp;gt; (loop for value being the hash-values of *my-hash*
           using (hash-key key)
           do (format t &amp;quot;~&amp;amp;~A -&amp;gt; ~A&amp;quot; key value))
FIRST-KEY -&amp;gt; ONE
SECOND-KEY -&amp;gt; TWO
THIRD-KEY -&amp;gt; NIL
NIL -&amp;gt; NIL-VALUE
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Last, we also have &lt;a href=&#34;cl21.htm&#34;&gt;cl21&lt;/a&gt;&amp;rsquo;s &lt;code&gt;(doeach ((key val) *hash*) …)&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&#34;traversign-keys-or-values&#34;&gt;Traversign keys or values&lt;/h4&gt;

&lt;p&gt;To map over keys or values we can again rely on Alexandria with
&lt;code&gt;maphash-keys&lt;/code&gt; and &lt;code&gt;maphash-values&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&#34;count&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;counting-the-entries-in-a-hash-table&#34;&gt;Counting the Entries in a Hash Table&lt;/h3&gt;

&lt;p&gt;No need to use your fingers - Common Lisp has a built-in function to
do it for you:
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_hash_1.htm&#34;&gt;&lt;code&gt;hash-table-count&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&amp;gt; (hash-table-count *my-hash*)
0
CL-USER&amp;gt; (setf (gethash &#39;first *my-hash*) 1)
1
CL-USER&amp;gt; (setf (gethash &#39;second *my-hash*) 2)
2
CL-USER&amp;gt; (setf (gethash &#39;third *my-hash*) 3)
3
CL-USER&amp;gt; (hash-table-count *my-hash*)
3
CL-USER&amp;gt; (setf (gethash &#39;second *my-hash*) &#39;two)
TWO
CL-USER&amp;gt; (hash-table-count *my-hash*)
3
CL-USER&amp;gt; (clrhash *my-hash*)
#&amp;lt;EQL hash table, 0 entries {48205F35}&amp;gt;
CL-USER&amp;gt; (hash-table-count *my-hash*)
0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a name=&#34;size&#34;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;performance-issues-the-size-of-your-hash-table&#34;&gt;Performance Issues: The Size of your Hash Table&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;make-hash-table&lt;/code&gt; function has a couple of optional parameters
which control the initial size of your hash table and how it&amp;rsquo;ll grow
if it needs to grow. This can be an important performance issue if
you&amp;rsquo;re working with large hash tables. Here&amp;rsquo;s an (admittedly not very
scientific) example with &lt;a href=&#34;http://www.cons.org/cmucl&#34;&gt;CMUCL&lt;/a&gt; pre-18d on
Linux:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&amp;gt; (hash-table-size *my-hash*)
65
CL-USER&amp;gt; (hash-table-rehash-size *my-hash*)
1.5
CL-USER&amp;gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.27 seconds of real time
  0.25 seconds of user run time
  0.02 seconds of system run time
  0 page faults and
  8754768 bytes consed.
NIL
CL-USER&amp;gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.05 seconds of real time
  0.05 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The values for
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_hash_4.htm&#34;&gt;&lt;code&gt;hash-table-size&lt;/code&gt;&lt;/a&gt;
and
&lt;a href=&#34;http://www.lispworks.com/documentation/HyperSpec/Body/f_hash_2.htm&#34;&gt;&lt;code&gt;hash-table-rehash-size&lt;/code&gt;&lt;/a&gt;
are implementation-dependent. In our case, CMUCL chooses and initial
size of 65, and it will increase the size of the hash by 50 percent
whenever it needs to grow. Let&amp;rsquo;s see how often we have to re-size the
hash until we reach the final size&amp;hellip;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (log (/ 100000 65) 1.5)
18.099062
CL-USER&amp;gt; (let ((size 65)) (dotimes (n 20) (print (list n size)) (setq size (* 1.5 size))))
(0 65)
(1 97.5)
(2 146.25)
(3 219.375)
(4 329.0625)
(5 493.59375)
(6 740.3906)
(7 1110.5859)
(8 1665.8789)
(9 2498.8184)
(10 3748.2275)
(11 5622.3413)
(12 8433.512)
(13 12650.268)
(14 18975.402)
(15 28463.104)
(16 42694.656)
(17 64041.984)
(18 96062.98)
(19 144094.47)
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The hash has to be re-sized 19 times until it&amp;rsquo;s big enough to hold
100,000 entries. That explains why we saw a lot of consing and why it
took rather long to fill the hash table. It also explains why the
second run was much faster - the hash table already had the correct
size.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a faster way to do it:
If we know in advance how big our hash will be, we can start with the right size:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table :size 100000))
*MY-HASH*
CL-USER&amp;gt; (hash-table-size *my-hash*)
100000
CL-USER&amp;gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.04 seconds of real time
  0.04 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s obviously much faster. And there was no consing involved
because we didn&amp;rsquo;t have to re-size at all. If we don&amp;rsquo;t know the final
size in advance but can guess the growth behaviour of our hash table
we can also provide this value to &lt;code&gt;make-hash-table&lt;/code&gt;. We can provide an
integer to specify absolute growth or a float to specify relative
growth.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER&amp;gt; (defparameter *my-hash* (make-hash-table :rehash-size 100000))
*MY-HASH*
CL-USER&amp;gt; (hash-table-size *my-hash*)
65
CL-USER&amp;gt; (hash-table-rehash-size *my-hash*)
100000
CL-USER&amp;gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.07 seconds of real time
  0.05 seconds of user run time
  0.01 seconds of system run time
  0 page faults and
  2001360 bytes consed.
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also rather fast (we only needed one re-size) but much more consing
because almost the whole hash table (minus 65 initial elements) had to
be built during the loop.&lt;/p&gt;

&lt;p&gt;Note that you can also specify the &lt;code&gt;rehash-threshold&lt;/code&gt; while creating a
new hash table. One final remark: Your implementation is allowed to
&lt;em&gt;completely ignore&lt;/em&gt; the values provided for &lt;code&gt;rehash-size&lt;/code&gt; and
&lt;code&gt;rehash-threshold&lt;/code&gt;&amp;hellip;&lt;/p&gt;

&lt;h2 id=&#34;alist&#34;&gt;Alist&lt;/h2&gt;

&lt;p&gt;An association list is a list of cons cells.&lt;/p&gt;

&lt;p&gt;This simple example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-alist (list (cons &#39;foo &amp;quot;foo&amp;quot;)
                             (cons &#39;bar &amp;quot;bar&amp;quot;)))
;; =&amp;gt; ((FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[o|o]---[o|/]
 |       |
 |      [o|o]---&amp;quot;bar&amp;quot;
 |       |
 |      BAR
 |
[o|o]---&amp;quot;foo&amp;quot;
 |
FOO
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The constructor &lt;code&gt;pairlis&lt;/code&gt; associates a list of keys and a list of values:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(pairlis &#39;(:foo :bar)
         &#39;(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;))
;; =&amp;gt; ((:BAR . &amp;quot;bar&amp;quot;) (:FOO . &amp;quot;foo&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To get a key, we have &lt;code&gt;assoc&lt;/code&gt; (use &lt;code&gt;:test &#39;equal&lt;/code&gt; when your keys are
strings, as usual). It returns the whole cons cell, so you may want to
use &lt;code&gt;cdr&lt;/code&gt; or &lt;code&gt;second&lt;/code&gt; to get the value. There is &lt;code&gt;assoc-if&lt;/code&gt;, and
&lt;code&gt;rassoc&lt;/code&gt; to get a cons cell by its value.&lt;/p&gt;

&lt;p&gt;To add a key, we &lt;code&gt;push&lt;/code&gt; another cons cell:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(push (cons &#39;team &amp;quot;team&amp;quot;) my-alist)
;; =&amp;gt; ((TEAM . &amp;quot;team&amp;quot;) (FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can use &lt;code&gt;pop&lt;/code&gt; and other functions that operate on lists, like &lt;code&gt;remove&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(remove :team my-alist)
;; =&amp;gt; ((:TEAM . &amp;quot;team&amp;quot;) (FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;)) ;; didn&#39;t remove anything
(remove :team my-alist :key &#39;car)
;; =&amp;gt; ((FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;)) ;; returns a copy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove only one element with &lt;code&gt;:count&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(push (cons &#39;bar &amp;quot;bar2&amp;quot;) my-alist)
;; =&amp;gt; ((BAR . &amp;quot;bar2&amp;quot;) (TEAM . &amp;quot;team&amp;quot;) (FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;)) ;; twice the &#39;bar key
(remove &#39;bar my-alist :key &#39;car :count 1)
;; =&amp;gt; ((TEAM . &amp;quot;team&amp;quot;) (FOO . &amp;quot;foo&amp;quot;) (BAR . &amp;quot;bar&amp;quot;))
;; because otherwise:
(remove &#39;bar my-alist :key &#39;car)
;; =&amp;gt; ((TEAM . &amp;quot;team&amp;quot;) (FOO . &amp;quot;foo&amp;quot;)) ;; no more &#39;bar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the
&lt;a href=&#34;https://common-lisp.net/project/alexandria/draft/alexandria.html#Conses&#34;&gt;Alexandria&lt;/a&gt;
library, see some functions like &lt;code&gt;remove-from-plist&lt;/code&gt;, &lt;code&gt;alist-plist&lt;/code&gt;,…&lt;/p&gt;

&lt;h2 id=&#34;plist&#34;&gt;Plist&lt;/h2&gt;

&lt;p&gt;A property list is simply a list that alternates a key, a value, and
so on, where its keys are symbols (we can not set its &lt;code&gt;:test&lt;/code&gt;). More
precisely, it first has a cons cell whose &lt;code&gt;car&lt;/code&gt; is the key, whose
&lt;code&gt;cdr&lt;/code&gt; points to the following cons cell whose &lt;code&gt;car&lt;/code&gt; is the
value.&lt;/p&gt;

&lt;p&gt;For example this plist:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-plist (list &#39;foo &amp;quot;foo&amp;quot; &#39;bar &amp;quot;bar&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[o|o]---[o|o]---[o|o]---[o|/]
 |       |       |       |
FOO     &amp;quot;foo&amp;quot;   BAR     &amp;quot;bar&amp;quot;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We access an element with &lt;code&gt;getf (list elt)&lt;/code&gt; (it returns the value)
(the list comes as first element),&lt;/p&gt;

&lt;p&gt;we remove an element with &lt;code&gt;remf&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defparameter my-plist (list &#39;foo &amp;quot;foo&amp;quot; &#39;bar &amp;quot;bar&amp;quot;))
;; =&amp;gt; (FOO &amp;quot;foo&amp;quot; BAR &amp;quot;bar&amp;quot;)
(setf (getf my-plist &#39;foo) &amp;quot;foo!!!&amp;quot;)
;; =&amp;gt; &amp;quot;foo!!!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;tree&#34;&gt;Tree&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tree-equal&lt;/code&gt;, &lt;code&gt;copy-tree&lt;/code&gt;. They descend recursively into the car and
the cdr of the cons cells they visit.&lt;/p&gt;

&lt;h3 id=&#34;sycamore-purely-functional-weight-balanced-binary-trees&#34;&gt;Sycamore - purely functional weight-balanced binary trees&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/ndantam/sycamore&#34;&gt;https://github.com/ndantam/sycamore&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast, purely functional weight-balanced binary trees.

&lt;ul&gt;
&lt;li&gt;Leaf nodes are simple-vectors, greatly reducing tree height.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Interfaces for tree Sets and Maps (dictionaries).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Rope_(data_structure)&#34;&gt;Ropes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Purely functional &lt;a href=&#34;http://en.wikipedia.org/wiki/Pairing_heap&#34;&gt;pairing heaps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Purely functional amortized queue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See more in other resources !&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Common Lisp Async Web Scraping</title>
      <link>/blog/common-lisp-async-web-scraping/</link>
      <pubDate>Thu, 29 Jun 2017 17:47:41 +0100</pubDate>
      
      <guid>/blog/common-lisp-async-web-scraping/</guid>
      <description>

&lt;p&gt;The set of tools to do web scraping in Common Lisp is pretty complete
and pleasant. In this short tutorial we&amp;rsquo;ll see how to make http
requests, parse html, extract content and do asynchronous requests.&lt;/p&gt;

&lt;p&gt;Our simple task will be to extract the list of links on the CL
Cookbook&amp;rsquo;s index page and check if they are reachable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Best read in &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/web-scraping.html&#34;&gt;the Cookbook&lt;/a&gt; !&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll use the following libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/fukamachi/dexador&#34;&gt;Dexador&lt;/a&gt; - an HTTP client
(that aims at replacing the venerable Drakma),&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shinmera.github.io/plump/&#34;&gt;Plump&lt;/a&gt; - a markup parser, that works on malformed HTML,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shinmera.github.io/lquery/&#34;&gt;Lquery&lt;/a&gt; - a DOM manipulation
library, to extract content from our Plump result,&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lparallel.org/pmap-family/&#34;&gt;lparallel&lt;/a&gt; -  a library for parallel programming (read more in the &lt;a href=&#34;process.html&#34;&gt;process section&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before starting let&amp;rsquo;s install those libraries with Quicklisp:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(ql:quickload &#39;(:dexador :plump :lquery :lparallel))
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- markdown-toc start - Don&#39;t edit this section. Run M-x markdown-toc-generate-toc again --&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#http-requests&#34;&gt;HTTP Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#parsing-and-extracting-content-with-css-selectors&#34;&gt;Parsing and extracting content with CSS selectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#async-requests&#34;&gt;Async requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- markdown-toc end --&gt;

&lt;h2 id=&#34;http-requests&#34;&gt;HTTP Requests&lt;/h2&gt;

&lt;p&gt;Easy things first. Install Dexador. Then we use the &lt;code&gt;get&lt;/code&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *url* &amp;quot;https://lispcookbook.github.io/cl-cookbook/&amp;quot;)
(defvar *request* (dex:get *url*))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This returns a list of values: the whole page content, the return code
(200), the response headers, the uri and the stream.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;&amp;lt;!DOCTYPE html&amp;gt;
 &amp;lt;html lang=\&amp;quot;en\&amp;quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Home &amp;amp;ndash; the Common Lisp Cookbook&amp;lt;/title&amp;gt;
    […]
    &amp;quot;
200
#&amp;lt;HASH-TABLE :TEST EQUAL :COUNT 19 {1008BF3043}&amp;gt;
#&amp;lt;QURI.URI.HTTP:URI-HTTPS https://lispcookbook.github.io/cl-cookbook/&amp;gt;
#&amp;lt;CL+SSL::SSL-STREAM for #&amp;lt;FD-STREAM for &amp;quot;socket 192.168.0.23:34897, peer: 151.101.120.133:443&amp;quot; {100781C133}&amp;gt;&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remember, in Slime we can inspect the objects with a right-click on
them.&lt;/p&gt;

&lt;h2 id=&#34;parsing-and-extracting-content-with-css-selectors&#34;&gt;Parsing and extracting content with CSS selectors&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ll use &lt;code&gt;Plump&lt;/code&gt; to parse the html and &lt;code&gt;Lquery&lt;/code&gt; to extract
content. They have nice documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://shinmera.github.io/plump/&#34;&gt;https://shinmera.github.io/plump/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shinmera.github.io/lquery/&#34;&gt;https://shinmera.github.io/lquery/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *parsed-content* (plump:parse *request*))
;; =&amp;gt; *PARSED-CONTENT**
*parsed-content**
;; =&amp;gt; #&amp;lt;PLUMP-DOM:ROOT {1009EE5FE3}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we&amp;rsquo;ll extract the links with CSS selectors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: to find out what should be the CSS selector of the element
I&amp;rsquo;m interested in, I right click on an element in the browser and I
choose &amp;ldquo;Inspect element&amp;rdquo;. This opens up the inspector of my browser&amp;rsquo;s
web dev tool and I can study the page structure.&lt;/p&gt;

&lt;p&gt;So the links I want to extract are in a page with an &lt;code&gt;id&lt;/code&gt; of value
&amp;ldquo;content&amp;rdquo;, and they are in regular list elements (&lt;code&gt;li&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s try something:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$  *parsed-content* &amp;quot;#content li&amp;quot;)
;; =&amp;gt; #(#&amp;lt;PLUMP-DOM:ELEMENT li {100B3263A3}&amp;gt; #&amp;lt;PLUMP-DOM:ELEMENT li {100B3263E3}&amp;gt;
;;  #&amp;lt;PLUMP-DOM:ELEMENT li {100B326423}&amp;gt; #&amp;lt;PLUMP-DOM:ELEMENT li {100B326463}&amp;gt;
;;  #&amp;lt;PLUMP-DOM:ELEMENT li {100B3264A3}&amp;gt; #&amp;lt;PLUMP-DOM:ELEMENT li {100B3264E3}&amp;gt;
;;  #&amp;lt;PLUMP-DOM:ELEMENT li {100B326523}&amp;gt; #&amp;lt;PLUMP-DOM:ELEMENT li {100B326563}&amp;gt;
;;  #&amp;lt;PLUMP-DOM:ELEMENT li {100B3265A3}&amp;gt; #&amp;lt;PLUMP-DOM:ELEMENT li {100B3265E3}&amp;gt;
;;  #&amp;lt;PLUMP-DOM:ELEMENT li {100B326623}&amp;gt; #&amp;lt;PLUMP-DOM:ELEMENT li {100B326663}&amp;gt;
;;  […]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wow it works ! We get here a vector of plump elements.&lt;/p&gt;

&lt;p&gt;Since it is a vector we could map over them with &lt;code&gt;(map &#39;vector (lambda
(elt) (…)) *)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But I&amp;rsquo;d like to easily check what those elements are. To see their textual
content we can append &lt;code&gt;(text)&lt;/code&gt; to our lquery form:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$  *parsed-content* &amp;quot;#content&amp;quot; (text))
#(&amp;quot;License&amp;quot; &amp;quot;Editor support&amp;quot; &amp;quot;Strings&amp;quot; &amp;quot;Dates and Times&amp;quot; &amp;quot;Hash Tables&amp;quot;
  &amp;quot;Pattern Matching / Regular Expressions&amp;quot; &amp;quot;Functions&amp;quot; &amp;quot;Loop&amp;quot; &amp;quot;Input/Output&amp;quot;
  &amp;quot;Files and Directories&amp;quot; &amp;quot;Packages&amp;quot; &amp;quot;Macros and Backquote&amp;quot;
  &amp;quot;CLOS (the Common Lisp Object System)&amp;quot; &amp;quot;Sockets&amp;quot; &amp;quot;Interfacing with your OS&amp;quot;
  &amp;quot;Foreign Function Interfaces&amp;quot; &amp;quot;Threads&amp;quot; &amp;quot;Defining Systems&amp;quot;
  &amp;quot;Using the Win32 API&amp;quot; &amp;quot;Testing&amp;quot; &amp;quot;Miscellaneous&amp;quot; &amp;quot;License&amp;quot; &amp;quot;Marco Antoniotti&amp;quot;
  &amp;quot;Zach Beane&amp;quot; &amp;quot;Pierpaolo Bernardi&amp;quot; &amp;quot;Christopher Brown&amp;quot; &amp;quot;Frederic Brunel&amp;quot;
  &amp;quot;Jeff Caldwell&amp;quot; &amp;quot;Bill Clementson&amp;quot; &amp;quot;Martin Cracauer&amp;quot; &amp;quot;Gerald Doussot&amp;quot;
  &amp;quot;Paul Foley&amp;quot; &amp;quot;Jörg-Cyril
  […]
  &amp;quot;Edi Weitz&amp;quot; &amp;quot;Fernando Borretti&amp;quot; &amp;quot;lisp-lang.org&amp;quot; &amp;quot;The Awesome-cl list&amp;quot;
  &amp;quot;The Common Lisp HyperSpec by Kent M. Pitman&amp;quot; &amp;quot;The Common Lisp UltraSpec&amp;quot;
  &amp;quot;Practical Common Lisp by Peter Seibel&amp;quot;
  &amp;quot;Common Lisp Recipes by Edmund Weitz, published in 2016,&amp;quot;
  […]
  &amp;quot;A Tutorial on Good Lisp Style by Peter Norvig and Kent Pitman&amp;quot;
  &amp;quot;Lisp and Elements of Style by Nick Levine&amp;quot;
  &amp;quot;Pascal Costanza’s Highly Opinionated Guide to Lisp&amp;quot;
  &amp;quot;Loving Lisp - the Savy Programmer’s Secret Weapon by Mark Watson&amp;quot;
  &amp;quot;FranzInc, a company selling Common Lisp and Graph Database solutions.&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Allright, so we see we are manipulating what we want. Now to get their
href, a quick look at lquery&amp;rsquo;s doc and:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(lquery:$  *parsed-content* &amp;quot;#content li a&amp;quot; (attr :href))
;; =&amp;gt; #(&amp;quot;license.html&amp;quot; &amp;quot;editor-support.html&amp;quot; &amp;quot;strings.html&amp;quot; &amp;quot;dates_and_times.html&amp;quot;
;;  &amp;quot;hashes.html&amp;quot; &amp;quot;pattern_matching.html&amp;quot; &amp;quot;functions.html&amp;quot; &amp;quot;loop.html&amp;quot; &amp;quot;io.html&amp;quot;
;;  &amp;quot;files.html&amp;quot; &amp;quot;packages.html&amp;quot; &amp;quot;macros.html&amp;quot;
;;  &amp;quot;/cl-cookbook/clos-tutorial/index.html&amp;quot; &amp;quot;sockets.html&amp;quot; &amp;quot;os.html&amp;quot; &amp;quot;ffi.html&amp;quot;
;;  &amp;quot;process.html&amp;quot; &amp;quot;systems.html&amp;quot; &amp;quot;win32.html&amp;quot; &amp;quot;testing.html&amp;quot; &amp;quot;misc.html&amp;quot;
;;  &amp;quot;license.html&amp;quot; &amp;quot;mailto:xach@xach.com&amp;quot; &amp;quot;mailto:skeptomai@mac.com&amp;quot;
;;  &amp;quot;mailto:brunel@mail.dotcom.fr&amp;quot; &amp;quot;mailto:jdcal@yahoo.com&amp;quot;
;;  &amp;quot;mailto:bill_clementson@yahoo.com&amp;quot; &amp;quot;mailto:gdoussot@yahoo.com&amp;quot;
;;  […]
;;  &amp;quot;mailto:matthieu@matthieu-villeneuve.net&amp;quot; &amp;quot;mailto:edi@agharta.de&amp;quot;
;;  &amp;quot;http://lisp-lang.org/&amp;quot; &amp;quot;https://github.com/CodyReichert/awesome-cl&amp;quot;
;;  &amp;quot;http://www.lispworks.com/documentation/HyperSpec/Front/index.htm&amp;quot;
;;  &amp;quot;http://phoe.tymoon.eu/clus/doku.php&amp;quot; &amp;quot;http://www.gigamonkeys.com/book/&amp;quot;
;;  […]
;;  &amp;quot;http://www.nicklevine.org/declarative/lectures/&amp;quot;
;;  &amp;quot;http://www.p-cos.net/lisp/guide.html&amp;quot; &amp;quot;https://leanpub.com/lovinglisp/&amp;quot;
;;  &amp;quot;https://franz.com/&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice, we now have the list (well, a vector) of links of the
page. We&amp;rsquo;ll now write an async program to check and validate they are
reachable.&lt;/p&gt;

&lt;p&gt;External resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://codingsec.net/2016/12/select-specific-text-css-using-selectors/&#34;&gt;CSS selectors by example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;async-requests&#34;&gt;Async requests&lt;/h2&gt;

&lt;p&gt;In this example we&amp;rsquo;ll take the list of url from above and we&amp;rsquo;ll check
if they are reachable. We want to do this asynchronously, but to see
the benefits we&amp;rsquo;ll first do it synchronously !&lt;/p&gt;

&lt;p&gt;We need a bit of filtering first to exclude the email adresses (maybe
that was doable in the CSS selector ?).&lt;/p&gt;

&lt;p&gt;We put the vector of urls in a variable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *urls* (lquery:$  *parsed-content* &amp;quot;#content li a&amp;quot; (attr :href)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We remove the elements that start with &amp;ldquo;mailto:&amp;rdquo;: (a quick look at the
&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/strings.html&#34;&gt;strings&lt;/a&gt; page will help)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(remove-if (lambda (it) (string= it &amp;quot;mailto:&amp;quot; :start1 0 :end1 (length &amp;quot;mailto:&amp;quot;))) *urls*)
;; =&amp;gt; #(&amp;quot;license.html&amp;quot; &amp;quot;editor-support.html&amp;quot; &amp;quot;strings.html&amp;quot; &amp;quot;dates_and_times.html&amp;quot;
;;  […]
;;  &amp;quot;process.html&amp;quot; &amp;quot;systems.html&amp;quot; &amp;quot;win32.html&amp;quot; &amp;quot;testing.html&amp;quot; &amp;quot;misc.html&amp;quot;
;;  &amp;quot;license.html&amp;quot; &amp;quot;http://lisp-lang.org/&amp;quot;
;;  &amp;quot;https://github.com/CodyReichert/awesome-cl&amp;quot;
;;  &amp;quot;http://www.lispworks.com/documentation/HyperSpec/Front/index.htm&amp;quot;
;;  […]
;;  &amp;quot;https://franz.com/&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Actually before writting the &lt;code&gt;remove-if&lt;/code&gt; (which works on any sequence,
including vectors) I tested with a &lt;code&gt;(map &#39;vector …)&lt;/code&gt; to see that the
results where indeed &lt;code&gt;nil&lt;/code&gt; or &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a side note, there is a handy &lt;code&gt;starts-with-p&lt;/code&gt; function in
&lt;a href=&#34;https://github.com/vindarel/cl-str/&#34;&gt;cl-strings&lt;/a&gt; (disclainer: that&amp;rsquo;s our lib),
available in Quicklisp. So we could do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(map &#39;vector (lambda (it) (str:starts-with-p &amp;quot;mailto:&amp;quot; it)) *urls*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it also has an option to ignore or respect the case.&lt;/p&gt;

&lt;p&gt;While we&amp;rsquo;re at it, we&amp;rsquo;ll only consider links starting with &amp;ldquo;http&amp;rdquo;, in
order not to write too much stuff irrelevant to web scraping:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(remove-if-not (lambda (it) (string= it &amp;quot;http&amp;quot; :start1 0 :end1 (length &amp;quot;http&amp;quot;))) *) ;; note the remove-if-NOT
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Allright, we put this result in another variable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *filtered-urls* *)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and now to the real work. For every url, we want to request it and
check that its return code is 200. We have to ignore certain
errors. Indeed, a request can timeout, be redirected (we don&amp;rsquo;t want
that) or return an error code.&lt;/p&gt;

&lt;p&gt;To be in real conditions we&amp;rsquo;ll add a link that times out in our list:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(setf (aref *filtered-urls* 0) &amp;quot;http://lisp.org&amp;quot;)  ;; too bad indeed
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We&amp;rsquo;ll take the simple approach to ignore errors and return &lt;code&gt;nil&lt;/code&gt; in
that case. If all goes well, we return the return code, that should be
200.&lt;/p&gt;

&lt;p&gt;As we saw at the beginning, &lt;code&gt;dex:get&lt;/code&gt; returns many values, including
the return code. We&amp;rsquo;ll catch only this one with &lt;code&gt;nth-value&lt;/code&gt; (instead
of all of them with &lt;code&gt;multiple-value-bind&lt;/code&gt;) and we&amp;rsquo;ll use
&lt;code&gt;ignore-errors&lt;/code&gt;, that returns nil in case of an error. We could also
use &lt;code&gt;handler-case&lt;/code&gt; and catch specific error types (see examples in
dexador&amp;rsquo;s documentation) or (better yet ?) use &lt;code&gt;handler-bind&lt;/code&gt; to catch
any &lt;code&gt;condition&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(ignore-errors has the caveat that when there&amp;rsquo;s an error, we can not
return the element it comes from. We&amp;rsquo;ll get to our ends though.)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(map &#39;vector (lambda (it)
  (ignore-errors
    (nth-value 1 (dex:get it))))
  *filtered-urls*)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we get:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#(NIL 200 200 200 200 200 200 200 200 200 200 NIL 200 200 200 200 200 200 200
  200 200 200 200)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;update&lt;/em&gt;: we could write something like the following with
&lt;code&gt;handler-case&lt;/code&gt; to be more flexible:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt; (handler-case ( &amp;lt;code&amp;gt; )
   (error (c)
     ( &amp;lt;return sthg&amp;gt; )))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it works, but &lt;em&gt;it took a very long time&lt;/em&gt;. How much time precisely ?
with &lt;code&gt;(time …)&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Evaluation took:
  21.554 seconds of real time
  0.188000 seconds of total run time (0.172000 user, 0.016000 system)
  0.87% CPU
  55,912,081,589 processor cycles
  9,279,664 bytes consed
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;21 seconds ! Obviously this synchronous method isn&amp;rsquo;t efficient. We
wait 10 seconds for links that time out. It&amp;rsquo;s time to write and
measure and async version.&lt;/p&gt;

&lt;p&gt;After installing &lt;code&gt;lparallel&lt;/code&gt; and looking at
&lt;a href=&#34;https://lparallel.org/&#34;&gt;its documentation&lt;/a&gt;, we see that the parallel
map &lt;a href=&#34;https://lparallel.org/pmap-family/&#34;&gt;pmap&lt;/a&gt; seems to be what we
want. And it&amp;rsquo;s only a one word edit. Let&amp;rsquo;s try:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(time (lparallel:pmap &#39;vector
  (lambda (it)
    (ignore-errors (let ((status (nth-value 1 (dex:get it)))) status)))
  *filtered-urls*)
;;  Evaluation took:
;;  11.584 seconds of real time
;;  0.156000 seconds of total run time (0.136000 user, 0.020000 system)
;;  1.35% CPU
;;  30,050,475,879 processor cycles
;;  7,241,616 bytes consed
;;
;;#(NIL 200 200 200 200 200 200 200 200 200 200 NIL 200 200 200 200 200 200 200
;;  200 200 200 200)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Bingo. It still takes more than 10 seconds because we wait 10 seconds
for one request that times out. But otherwise it proceeds all the http
requests in parallel and so it is much faster.&lt;/p&gt;

&lt;p&gt;Shall we get the urls that aren&amp;rsquo;t reachable, remove them from our list
and measure the execution time in the sync and async cases ?&lt;/p&gt;

&lt;p&gt;What we do is: instead of returning only the return code, we check it
is valid and we return the url:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;... (if (and status (= 200 status)) it) ...
(defvar *valid-urls* *)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we get a vector of urls with a couple of &lt;code&gt;nil&lt;/code&gt;s: indeed, I thought I
would have only one unreachable url but I discovered another
one. Hopefully I have pushed a fix before you try this tutorial.&lt;/p&gt;

&lt;p&gt;But what are they ? We saw the status codes but not the urls :S We
have a vector with all the urls and another with the valid ones. We&amp;rsquo;ll
simply treat them as sets and compute their difference. This will show
us the bad ones. We must transform our vectors to lists for that.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(set-difference (coerce *filtered-urls* &#39;list)
                (coerce *valid-urls* &#39;list))
;; =&amp;gt; (&amp;quot;http://lisp-lang.org/&amp;quot; &amp;quot;http://www.psg.com/~dlamkins/sl/cover.html&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gotcha !&lt;/p&gt;

&lt;p&gt;BTW it takes 8.280 seconds of real time to me to check the list of
valid urls synchronously, and 2.857 seconds async.&lt;/p&gt;

&lt;p&gt;Have fun doing web scraping in CL !&lt;/p&gt;

&lt;p&gt;More helpful libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we could use &lt;a href=&#34;https://github.com/tsikov/vcr&#34;&gt;VCR&lt;/a&gt;, a store and
replay utility to set up repeatable tests or to speed up a bit our
experiments in the REPL.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/orthecreedence/cl-async&#34;&gt;cl-async&lt;/a&gt;,
&lt;a href=&#34;https://github.com/orthecreedence/carrier&#34;&gt;carrier&lt;/a&gt; and others
network, parallelism and concurrency libraries to see on the
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;awesome-cl&lt;/a&gt; list,
&lt;a href=&#34;http://www.cliki.net/&#34;&gt;Cliki&lt;/a&gt; or
&lt;a href=&#34;http://quickdocs.org/search?q=web&#34;&gt;Quickdocs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Chream/mockingbird&#34;&gt;Mockingbird&lt;/a&gt; is nice to mock
network requests in unit tests.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>How to Get a File Size (and others Posix Attributes like its mtime) in Common Lisp</title>
      <link>/blog/how-to-get-a-file-size-and-posix-file-attributes/</link>
      <pubDate>Fri, 16 Jun 2017 16:26:00 +0200</pubDate>
      
      <guid>/blog/how-to-get-a-file-size-and-posix-file-attributes/</guid>
      <description>

&lt;p&gt;There is nothing built-in since CL predates the posix standard.&lt;/p&gt;

&lt;p&gt;After a look at
&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;Awesome CL&lt;/a&gt;, the
&lt;a href=&#34;https://www.common-lisp.net/project/osicat/manual/osicat.html&#34;&gt;Osicat library&lt;/a&gt;
was my go-to package to look for such functionnality. There is its
&lt;code&gt;osicat-posix&lt;/code&gt; package indeed, even though it is undocumented
(&lt;a href=&#34;https://github.com/osicat/osicat/issues/20&#34;&gt;issue&lt;/a&gt;)…&lt;/p&gt;

&lt;p&gt;Now a look at the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/files.html#getting-file-attributes-size-access-time-with-the-osicat-library&#34;&gt;Cookbook&lt;/a&gt; is ok.&lt;/p&gt;

&lt;h2 id=&#34;osicat-osicat-posix&#34;&gt;osicat, osicat-posix&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;osicat-posix&lt;/code&gt; is included in &lt;code&gt;osicat&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload :osicat)
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(describe (osicat-posix:stat #P&amp;quot;/tmp/file&amp;quot;))

#&amp;lt;OSICAT-POSIX:STAT {1004F20C93}&amp;gt;
  [standard-object]

Slots with :INSTANCE allocation:
  DEV      = 2065
  INO      = 7349974
  MODE     = 33204
  NLINK    = 1
  UID      = 1000
  GID      = 1000
  RDEV     = 0
  SIZE     = 4304
  BLKSIZE  = 4096
  BLOCKS   = 16
  ATIME    = 1497626097
  MTIME    = 1497347216
  CTIME    = 1497347216
; No value
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and so we can access the slots with their related functions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;osicat-posix:stat-dev
osicat-posix:stat-gid
osicat-posix:stat-ino
osicat-posix:stat-uid
osicat-posix:stat-mode
osicat-posix:stat-rdev
osicat-posix:stat-size
osicat-posix:stat-atime
osicat-posix:stat-ctime
osicat-posix:stat-mtime
osicat-posix:stat-nlink
osicat-posix:stat-blocks
osicat-posix:stat-blksize
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so for example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(let ((stat (osicat-posix:stat #P&amp;quot;./files.md&amp;quot;)))
  (osicat-posix:stat-size stat))  ;; =&amp;gt; 10629
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;trivial-file-size&#34;&gt;Trivial-file-size&lt;/h2&gt;

&lt;p&gt;Now for the size there&amp;rsquo;s also the lightweight (and portable)
&lt;a href=&#34;https://github.com/TBRSS/trivial-file-size&#34;&gt;trivial-file-size&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This library exports a single function, file-size-in-octets. It returns the size of a file in bytes, using system calls when possible.&lt;/p&gt;

&lt;p&gt;The canonical way to determine the size of a file in bytes, using Common Lisp, is to open the file with an element type of (unsigned-byte 8) and then calculate the length of the stream. This is less than ideal. In most cases it would be better to get the size of the file from its metadata, using a system call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The author new about osicat-posix.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to access url query parameters in Clack, Lucerne or Caveman</title>
      <link>/blog/how-to-access-url-query-parameters-in-clack-lucerne-or-caveman/</link>
      <pubDate>Thu, 04 May 2017 12:59:30 +0200</pubDate>
      
      <guid>/blog/how-to-access-url-query-parameters-in-clack-lucerne-or-caveman/</guid>
      <description>

&lt;p&gt;&lt;strong&gt;edit&lt;/strong&gt;: I found &lt;a href=&#34;https://github.com/joaotavora/snooze&#34;&gt;Snooze&lt;/a&gt; (by
Sly and Yasnippet&amp;rsquo;s author) easier and cleaner in this regard. It also
has built-in settings to choose where to catch errors: with Slime&amp;rsquo;s
debugger, with a full stacktrace in the browser or displaying a custom
error page.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re using Lucerne don&amp;rsquo;t search more like I did, its
&lt;code&gt;with-params&lt;/code&gt; macro works with url query parameters (as well as POST
parameters).&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re accessing the url &lt;code&gt;hello?search=kw&lt;/code&gt;, this works:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;@route app &amp;quot;/hello&amp;quot;
(defview index (name)
  (with-params (search)
    (render-template (+index+)
                     :search search)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An illustration with a POST parameter from the &amp;ldquo;utweet&amp;rdquo; example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;@route app (:post &amp;quot;/tweet&amp;quot;)
(defview tweet ()
  (if (lucerne-auth:logged-in-p)
      (let ((user (current-user)))
        (with-params (tweet)
          (utweet.models:tweet user tweet))
        (redirect &amp;quot;/&amp;quot;))
      (render-template (+index+)
                       :error &amp;quot;You are not logged in.&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The macro is implemented like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;; https://github.com/eudoxia0/lucerne/blob/master/src/http.lisp
(defmacro with-params (params &amp;amp;body body)
  &amp;quot;Extract the parameters in @cl:param(param) from the @c(*request*), and bind
them for use in @cl:param(body).&amp;quot;
  `(let ,(loop for param in params collecting
               `(,param (let ((str (parameter *request*
                                              ,(intern (string-downcase
                                                        (symbol-name param))
                                                       :keyword))))
                          (if (equal str &amp;quot;&amp;quot;)
                              nil
                              str))))
     ,@body))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For Caveman it is &lt;a href=&#34;https://github.com/fukamachi/caveman#structured-querypost-parameters&#34;&gt;possible&lt;/a&gt; but a bit awkward and &lt;a href=&#34;https://github.com/fukamachi/caveman/issues/22&#34;&gt;inconsistent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s an example for Ningle
&lt;a href=&#34;https://stackoverflow.com/questions/43778570/how-to-get-url-query-parameters-in-clack-lucerne-or-caveman&#34;&gt;on the related StackOverflow question&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;and-in-clack-generally&#34;&gt;And in Clack generally ?&lt;/h3&gt;

&lt;p&gt;It is only scarcely documented on Clack&amp;rsquo;s
&lt;a href=&#34;http://quickdocs.org/clack/api#package-CLACK.REQUEST&#34;&gt;api documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can access the parameters with &lt;code&gt;(clack.request:query-parameter
lucerne:*request*)&lt;/code&gt;. So to get the value of a given param:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(assoc &amp;quot;a-param&amp;quot; (clack.request:query-parameter lucerne:*request*) :test &#39;string=)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and this returns the key and the value, so we need another &lt;code&gt;cdr&lt;/code&gt; to get the value…&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun query-param (param)
  (cdr (assoc param (clack.request:query-parameter lucerne:*request*) :test #&#39;string=)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://jasom.github.io/clack-tutorial/pages/getting-started-with-clack/&#34;&gt;https://jasom.github.io/clack-tutorial/pages/getting-started-with-clack/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Is There Something Like Clojure&#39;s Figwheel for interactive web dev with the browser in Common Lisp ?</title>
      <link>/blog/is-there-something-like-figwheel-for-common-lisp/</link>
      <pubDate>Thu, 04 May 2017 12:32:01 +0200</pubDate>
      
      <guid>/blog/is-there-something-like-figwheel-for-common-lisp/</guid>
      <description>&lt;p&gt;Looks like there is:
&lt;a href=&#34;https://github.com/johnmastro/trident-mode.el&#34;&gt;trident-mode&lt;/a&gt;, an
&lt;em&gt;&amp;ldquo;Emacs minor mode for live Parenscript interaction&amp;rdquo;&lt;/em&gt;, based on
&lt;a href=&#34;https://github.com/skeeto/skewer-mode&#34;&gt;skewer&lt;/a&gt; but: trident-mode
doesn&amp;rsquo;t seem to be used in the wild (while skewer-mode is) and I don&amp;rsquo;t
know Figwheel so all I can say is that it seems a bit different:
instead of letting us selectively evaluate and send code to the
browser, Figwheels seems to rebuild the entire project and send the
result when we write a file.&lt;/p&gt;

&lt;p&gt;I tried trident-mode quickly, it works and the author was
responsive. It offers commands and shortcuts to see the Javascript
code produced by Parenscript forms and (optionally) send them to the
browser.&lt;/p&gt;

&lt;p&gt;An example use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;((@ document write)
  (ps-html ((:a :href &amp;quot;foobar&amp;quot;) &amp;quot;blorg&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to evaluate with &lt;code&gt;trident-eval-dwim&lt;/code&gt;, which generates&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;document.write(&amp;quot;&amp;lt;A HREF=\&amp;quot;foobar\&amp;quot;&amp;gt;blorg&amp;lt;/A&amp;gt;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so it uses js to insert html into the DOM.
It doesn&amp;rsquo;t leverage Skewer&amp;rsquo;s capacity to send only html.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll update this post if/when I can.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/bhauman/lein-figwheel&#34;&gt;Figwheel&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;builds your ClojureScript code and hot loads it into the
 browser as you are coding!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Skewer&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Provides live interaction with JavaScript, CSS, and HTML in a web browser. Expressions are sent on-the-fly from an editing buffer to be evaluated in the browser, just like Emacs does with an inferior Lisp process in Lisp modes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and we can also connect to sites on servers we don&amp;rsquo;t control.&lt;/p&gt;

&lt;p&gt;They have demo videos.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Getting started: how to install a Common Lisp development environment</title>
      <link>/blog/getting-started/</link>
      <pubDate>Wed, 03 May 2017 10:41:33 +0200</pubDate>
      
      <guid>/blog/getting-started/</guid>
      <description>

&lt;p&gt;or &amp;ldquo;could not find recent and easy installation steps [fixed]&amp;ldquo;.&lt;/p&gt;

&lt;p&gt;When I started I was a bit confused by old instructions (google is not
good at CL), so hopefully this post will help show up recent and easy
steps and most of all, help every CL enthousiast discover
&lt;strong&gt;Portacle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;(and this post is editable through its &lt;a href=&#34;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/&#34;&gt;Gitlab repository&lt;/a&gt;)&lt;/p&gt;

&lt;h2 id=&#34;portable-a-multiplatform-development-environment&#34;&gt;Portable, a multiplatform development environment&lt;/h2&gt;

&lt;p&gt;The productive Shinmera was waiting for the last details to be fixed
before showing &lt;a href=&#34;https://portacle.github.io/&#34;&gt;Portacle&lt;/a&gt; but it was
already great. On GNU/Linux, MacOs or Windows, just download an
archive and click an icon to open Emacs ready to use for CL
development. It is that easy.&lt;/p&gt;

&lt;p&gt;It ships: Emacs (customized), the SBCL implementation, Slime (Emacs
IDE), Quicklisp (package manager) and Git. Emacs comes with a nice
theme, autocompletion in drop-downs (company-mode) and
&lt;a href=&#34;https://magit.vc/&#34;&gt;Magit&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;manual-install&#34;&gt;Manual install&lt;/h2&gt;

&lt;h3 id=&#34;lisp-implementation&#34;&gt;Lisp implementation&lt;/h3&gt;

&lt;p&gt;Install a CL implementation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apt-get install sbcl
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now you can run &lt;code&gt;sbcl&lt;/code&gt; and write lisp at the prompt:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(print &amp;quot;hello lisp!&amp;quot;)
(quit) ;; or C-d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;More are packaged for Debian and probably for your distro, notably
&lt;a href=&#34;https://gitlab.com/embeddable-common-lisp/ecl/&#34;&gt;ECL&lt;/a&gt;, and note that
you can install more easily with &lt;a href=&#34;https://github.com/roswell/roswell/wiki&#34;&gt;Roswell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you find the prompt horribly unfriendly (no history, no navigation…) use rlwrap:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apt-get install rlwrap
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and now this will be slightly better:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rwrap sbcl
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Even better, a slight wrapper around the SBCL REPL with readline
support (Emacs and Vim modes, history, etc):
&lt;a href=&#34;https://github.com/hellerve/sbcli&#34;&gt;sbcli&lt;/a&gt;, straightforward to use.&lt;/p&gt;

&lt;p&gt;But still, we really need an editor.&lt;/p&gt;

&lt;h3 id=&#34;editors-support&#34;&gt;Editors support&lt;/h3&gt;

&lt;p&gt;You&amp;rsquo;re not bound to Emacs, there&amp;rsquo;s good support for Vim, Sublime Text
(via the SublimeREPL package) and Atom.&lt;/p&gt;

&lt;p&gt;See the &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/editor-support.html&#34;&gt;Cookbook#editors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Emacs, &lt;a href=&#34;https://github.com/slime/slime&#34;&gt;Slime&lt;/a&gt; is the de-facto
solution (there&amp;rsquo;s also the Sly fork). It is in the GNU Elpa default
Emacs package repository, so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;M-x package-install RET slime RET
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(you may need a &lt;code&gt;M-x package-refresh-content&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now start Slime with &lt;code&gt;M-x slime&lt;/code&gt; and wait a few seconds that it starts
its backend (Swank server).&lt;/p&gt;

&lt;p&gt;Might help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using Emacs (and other instructions): &lt;a href=&#34;https://www.darkchestnut.com/2017/getting-started-with-common-lisp/#using-emacs&#34;&gt;https://www.darkchestnut.com/2017/getting-started-with-common-lisp/#using-emacs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://wikemacs.org/wiki/Common_Lisp&#34;&gt;http://wikemacs.org/wiki/Common_Lisp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Slime manual: &lt;a href=&#34;https://common-lisp.net/project/slime/doc/html/&#34;&gt;https://common-lisp.net/project/slime/doc/html/&lt;/a&gt; (see
the Emacs menu). In very short: compile a file with &lt;code&gt;C-c C-k&lt;/code&gt;,
compile one function with &lt;code&gt;C-c C-c&lt;/code&gt; and use it at the REPL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;quicklisp-package-manager&#34;&gt;Quicklisp package manager&lt;/h3&gt;

&lt;p&gt;To install &lt;a href=&#34;https://www.quicklisp.org/beta/&#34;&gt;Quicklisp&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;from anywhere, download this file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; wget https://beta.quicklisp.org/quicklisp.lisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;start a Lisp and load this file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sbcl --load quicklisp.lisp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;we get in the sbcl prompt. We have one Quicklisp command to type to
install it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(quicklisp-quickstart:install)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it will install itself in &lt;code&gt;~/quicklisp/quicklisp/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;it should output something like this, showing the basic commands:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;==================================================
2,846 bytes in 0.001 seconds (2779.30KB/sec)
Upgrading ASDF package from version 2.004 to version 2.009
; Fetching #&amp;lt;URL &amp;quot;http://beta.quicklisp.org/dist/quicklisp.txt&amp;quot;&amp;gt;
; 0.40KB
==================================================
408 bytes in 0.003 seconds (132.81KB/sec)

  ==== quicklisp installed ====

    To load a system, use: (ql:quickload &amp;quot;system-name&amp;quot;)

    To find systems, use: (ql:system-apropos &amp;quot;term&amp;quot;)

    To load Quicklisp every time you start Lisp, use: (ql:add-to-init-file)

    For more information, see http://www.quicklisp.org/beta/

NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Does it work ? Let&amp;rsquo;s try to install something:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload &amp;quot;dexador&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is installed but we want to have Quicklisp available everytime we
start sbcl. Otherwise we&amp;rsquo;d have to &lt;code&gt;load&lt;/code&gt; the file located at
&lt;code&gt;~/quicklisp/quicklisp/setup.lisp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each implementation uses a startup file, like our shells, so we can
add this into our &lt;code&gt;~/.sbclrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;;;; The following lines added by ql:add-to-init-file:
  #-quicklisp
  (let ((quicklisp-init (merge-pathnames &amp;quot;quicklisp/setup.lisp&amp;quot;
                                         (user-homedir-pathname))))
    (when (probe-file quicklisp-init)
      (load quicklisp-init)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To quit sbcl, &lt;code&gt;(quit)&lt;/code&gt; or &lt;code&gt;C-d&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Quicklisp is a bit different than others package managers and it is
not the only solution. That&amp;rsquo;s for another post.&lt;/p&gt;

&lt;h2 id=&#34;starting-a-project&#34;&gt;Starting a project&lt;/h2&gt;

&lt;p&gt;I advise &lt;a href=&#34;https://github.com/fukamachi/cl-project&#34;&gt;cl-project&lt;/a&gt; which,
unlike others (quickproject) also sets up tests.&lt;/p&gt;

&lt;p&gt;Now we can &lt;code&gt;C-c C-k&lt;/code&gt; the &lt;code&gt;.asd&lt;/code&gt; file and &lt;code&gt;(ql:quickload &amp;quot;my-app&amp;quot;)&lt;/code&gt; our
app in the Slime REPL. But this is for another post.&lt;/p&gt;

&lt;h2 id=&#34;managing-implementations-and-installing-libraries-in-the-command-line-roswell&#34;&gt;Managing implementations and installing libraries in the command line: Roswell&lt;/h2&gt;

&lt;p&gt;This is done together with &lt;a href=&#34;https://github.com/roswell/roswell/wiki&#34;&gt;Roswell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Roswell is in brew for MacOS, in linuxbrew, and it has a Debian package.&lt;/p&gt;

&lt;p&gt;It allows to install pinned versions of SBCL or of other
implementations (Embedable CL, Clozure CL,…) easily:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ros install sbcl/1.2.14
ros install sbcl  # the latest
ros install ccl-bin
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;what&amp;rsquo;s available ?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ros list versions
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;change the current lisp:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ros use sbcl/1.2.14
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Install scripts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ros install qlot
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Install packages:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ros install dexador  # http client
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it does more to help scripting and distributing software. See its wiki !&lt;/p&gt;

&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;a Debian package for CCL (2016): &lt;a href=&#34;http://mr.gy/blog/clozure-cl-deb.html&#34;&gt;http://mr.gy/blog/clozure-cl-deb.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>String manipulation is frustrating [fixed]</title>
      <link>/blog/string-manipulation-was-frustrating/</link>
      <pubDate>Tue, 02 May 2017 11:07:01 +0200</pubDate>
      
      <guid>/blog/string-manipulation-was-frustrating/</guid>
      <description>

&lt;p&gt;One of the first things I wanted to do in the REPL was some string
manipulation. But it was tedious.&lt;/p&gt;

&lt;p&gt;To trim whitespace, and I mean all whitespaces, we had to define
&lt;code&gt;#\Space #\Newline #\Backspace #\Tab #\Linefeed #\Page #\Return
#\Rubout&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To concatenate two strings: either giving an unusual &lt;code&gt;&#39;string&lt;/code&gt; argument to
&lt;code&gt;concatenate&lt;/code&gt;, like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(concatenate &#39;string &amp;quot;fo&amp;quot; &amp;quot;o&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;either we had to use a &lt;code&gt;format&lt;/code&gt; construct, which is another source of
frustration for (impatient) beginners, and sure isn&amp;rsquo;t straightforward
and self-explanatory.&lt;/p&gt;

&lt;p&gt;Many common stuff was split in various external libraries
(&lt;code&gt;cl-ppcre&lt;/code&gt;), and many common stuff was made more difficult than
necessary (weird format construct again, entering a regexp, thus
esaping what&amp;rsquo;s necessary, when all you want to do is simple search and
replace, dealing with strings&amp;rsquo; lengths and corner cases, lack of
verbs,… see below).&lt;/p&gt;

&lt;p&gt;And all of that with many inconsistencies (the string as first
argument, then as the last, etc).&lt;/p&gt;

&lt;p&gt;So I just joined everything in a little library, which has now more
features. Let&amp;rsquo;s see its code and its tests to learn at the canonical
way to do stuff, their shortcomings, and the library api at the same
time.&lt;/p&gt;

&lt;p&gt;I just don&amp;rsquo;t know how come this lib didn&amp;rsquo;t exist yet.&lt;/p&gt;

&lt;h2 id=&#34;str&#34;&gt;&lt;code&gt;str&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;You can install it with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ql:quickload &amp;quot;str&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See on &lt;a href=&#34;https://github.com/vindarel/cl-str&#34;&gt;https://github.com/vindarel/cl-str&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;package-definition&#34;&gt;Package definition&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(in-package #:asdf-user)

(defsystem :str
  :source-control (:git &amp;quot;git@github.com:vindarel/cl-s.git&amp;quot;)
  :description &amp;quot;Modern, consistent and terse Common Lisp string manipulation library.&amp;quot;
  :depends-on (:prove :cl-ppcre)  ;; &amp;lt;= depends only on cl-ppcre.
  :components ((:file &amp;quot;str&amp;quot;))
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;trim&#34;&gt;Trim&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defvar *whitespaces* &#39;(#\Space #\Newline #\Backspace #\Tab
                        #\Linefeed #\Page #\Return #\Rubout))

(defun trim-left (s)
  &amp;quot;Remove whitespaces at the beginning of s. &amp;quot;
  (string-left-trim *whitespaces* s))

(defun trim-right (s)
  &amp;quot;Remove whitespaces at the end of s.&amp;quot;
  (string-right-trim *whitespaces* s))


(defun trim (s)
  (string-trim *whitespaces* s))

&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;concat&#34;&gt;Concat&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun concat (&amp;amp;rest strings)
  &amp;quot;Join all the string arguments into one string.&amp;quot;
  (apply #&#39;concatenate &#39;string strings))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;join&#34;&gt;Join&lt;/h3&gt;

&lt;p&gt;Snippets on the old cookbook or stackoverflow advised to use a
&lt;code&gt;format&lt;/code&gt; construct. Which is weird, and causes problems if your
separator contains the &lt;code&gt;~&lt;/code&gt; symbol.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun join (separator strings)
  (let ((separator (replace-all &amp;quot;~&amp;quot; &amp;quot;~~&amp;quot; separator)))
    (format nil
            (concatenate &#39;string &amp;quot;~{~a~^&amp;quot; separator &amp;quot;~}&amp;quot;)
            strings)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(is &amp;quot;foo~bar&amp;quot;
    (join &amp;quot;~&amp;quot; &#39;(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;split&#34;&gt;Split&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;cl-ppcre&lt;/code&gt; takes a regexp, but we don&amp;rsquo;t need this for the basic cases
of &lt;code&gt;split&lt;/code&gt;. And disabling this regexp was not straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun split (separator s &amp;amp;key omit-nulls)
  &amp;quot;Split s into substring by separator (cl-ppcre takes a regex, we do not).&amp;quot;
  ;; cl-ppcre:split doesn&#39;t return a null string if the separator appears at the end of s.
  (let* ((val (concat s
                      (string separator)
                      ;; so we need an extra character, but not the user&#39;s.
                      (if (string-equal separator #\x) &amp;quot;y&amp;quot; &amp;quot;x&amp;quot;)))
         (res (butlast (cl-ppcre:split (cl-ppcre:quote-meta-chars (string separator)) val))))
    (if omit-nulls
        (remove-if (lambda (it) (empty? it)) res)
        res)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now: &lt;code&gt;(split &amp;quot;.&amp;quot; &amp;quot;foo.bar&amp;quot;)&lt;/code&gt; just works.&lt;/p&gt;

&lt;h3 id=&#34;repeat&#34;&gt;Repeat&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun repeat (count s)
  &amp;quot;Make a string of S repeated COUNT times.&amp;quot;
  (let ((result nil))
    (dotimes (i count)
      (setf result (cons s result)))
    (apply #&#39;concat result)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;replace-all&#34;&gt;Replace-all&lt;/h3&gt;

&lt;p&gt;This required to use cl-ppcre and one switch of it to avoid regexps.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun replace-all (old new s)
  &amp;quot;Replace `old` by `new` in `s`. Arguments are not regexs.&amp;quot;
  (let* ((cl-ppcre:*allow-quoting* t)
         (old (concatenate &#39;string  &amp;quot;\\Q&amp;quot; old))) ;; treat metacharacters as normal.
    (cl-ppcre:regex-replace-all old s new)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;starts-with-start-string&#34;&gt;starts-with? start string&lt;/h3&gt;

&lt;p&gt;The Lisp way was to check if the beginning of &amp;ldquo;string&amp;rdquo; contains
&amp;ldquo;start&amp;rdquo;, taking its length, dealing with corner cases,…&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun starts-with? (start s &amp;amp;key (ignore-case nil))
  &amp;quot;Return t if s starts with the substring &#39;start&#39;, nil otherwise.&amp;quot;
  (when (&amp;gt;= (length s) (length start))
    (let ((fn (if ignore-case #&#39;string-equal #&#39;string=)))
      (funcall fn s start :start1 0 :end1 (length start)))))

;; An alias:
;; Serapeum defines a &amp;quot;defalias&amp;quot;.
(setf (fdefinition &#39;starts-with-p) #&#39;starts-with?)

(defun ends-with? (end s &amp;amp;key (ignore-case nil))
  &amp;quot;Return t if s ends with the substring &#39;end&#39;, nil otherwise.&amp;quot;
  (when (&amp;gt;= (length s) (length end))
    (let ((fn (if ignore-case #&#39;string-equal #&#39;string=)))
      (funcall fn s end :start1 (- (length s) (length end))))))

(setf (fdefinition &#39;ends-with-p) #&#39;ends-with?)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usage illustrated by the tests:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(subtest &amp;quot;starts-with?&amp;quot;
  (ok (starts-with? &amp;quot;foo&amp;quot; &amp;quot;foobar&amp;quot;) &amp;quot;default case&amp;quot;)
  (ok (starts-with? &amp;quot;&amp;quot; &amp;quot;foo&amp;quot;) &amp;quot;with blank start&amp;quot;)
  (ok (not (starts-with? &amp;quot;rs&amp;quot; &amp;quot;&amp;quot;)) &amp;quot;with blank s&amp;quot;)
  (ok (not (starts-with? &amp;quot;foobar&amp;quot; &amp;quot;foo&amp;quot;)) &amp;quot;with shorter s&amp;quot;)
  (ok (starts-with? &amp;quot;&amp;quot; &amp;quot;&amp;quot;) &amp;quot;with everything blank&amp;quot;)
  (ok (not (starts-with? &amp;quot;FOO&amp;quot; &amp;quot;foobar&amp;quot;)) &amp;quot;don&#39;t ignore case&amp;quot;)
  (ok (starts-with-p &amp;quot;f&amp;quot; &amp;quot;foo&amp;quot;) &amp;quot;starts-with-p alias&amp;quot;)
  (ok (starts-with? &amp;quot;FOO&amp;quot; &amp;quot;foobar&amp;quot; :ignore-case t) &amp;quot;ignore case&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;predicates-empty-blank&#34;&gt;Predicates: empty? blank?&lt;/h3&gt;

&lt;p&gt;There was no built-in to make those differences.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun empty? (s)
  &amp;quot;Is s nil or the empty string ?&amp;quot;
  (or (null s) (string-equal &amp;quot;&amp;quot; s)))

(defun emptyp (s)
  &amp;quot;Is s nil or the empty string ?&amp;quot;
  (empty? s))

(defun blank? (s)
  &amp;quot;Is s nil or only contains whitespaces ?&amp;quot;
  (or (null s) (string-equal &amp;quot;&amp;quot; (trim s))))

(defun blankp (s)
  &amp;quot;Is s nil or only contains whitespaces ?&amp;quot;
  (blank? s))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;words-unwords-lines-unlines&#34;&gt;words, unwords, lines, unlines&lt;/h3&gt;

&lt;p&gt;Classic stuff:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun words (s &amp;amp;key (limit 0))
  &amp;quot;Return list of words, which were delimited by white space. If the optional limit is 0 (the default), trailing empty strings are removed from the result list (see cl-ppcre).&amp;quot;
  (if (not s)
      nil
      (cl-ppcre:split &amp;quot;\\s+&amp;quot; (trim-left s) :limit limit)))

(defun unwords (strings)
  &amp;quot;Join the list of strings with a whitespace.&amp;quot;
  (join &amp;quot; &amp;quot; strings))

(defun lines (s &amp;amp;key omit-nulls)
  &amp;quot;Split the string by newline characters and return a list of lines.&amp;quot;
  (split #\NewLine s :omit-nulls omit-nulls))

(defun unlines (strings)
  &amp;quot;Join the list of strings with a newline character.&amp;quot;
  (join (make-string 1 :initial-element #\Newline) strings))
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;substring&#34;&gt;Substring&lt;/h3&gt;

&lt;p&gt;The builtin &lt;code&gt;subseq&lt;/code&gt; is much poorer compared to what we have in other languages.&lt;/p&gt;

&lt;p&gt;Take Python, we can do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;foo&amp;quot;[:-1] # negative index and starting from the end
&amp;quot;foo&amp;quot;[0:100] # end is too large, thus it returns the entire array.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This was not possible with &lt;code&gt;subseq&lt;/code&gt;, it throws a condition. Nothing
found in Alexandria or other helper libraries.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(defun substring (start end s)
  &amp;quot;Return the substring of `s&#39; from `start&#39; to `end&#39;.

It uses `subseq&#39; with differences:
- argument order, s at the end
- `start&#39; and `end&#39; can be lower than 0 or bigger than the length of s.

- for convenience `end&#39; can be nil or t to denote the end of the string.
&amp;quot;
  (let* ((s-length (length s))
         (end (cond
                ((null end) s-length)
                ((eq end t) s-length)
                (t end))))
    (setf start (max 0 start))
    (if (&amp;gt; start s-length)
        &amp;quot;&amp;quot;
        (progn
          (setf end (min end s-length))
          (when (&amp;lt; end (- s-length))
            (setf end 0))
          (when (&amp;lt; end 0)
            (setf end (+ s-length end)))
          (if (&amp;lt; end start)
              &amp;quot;&amp;quot;
              (subseq s start end))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usage:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(subtest &amp;quot;substring&amp;quot;
  (is &amp;quot;abcd&amp;quot; (substring 0 4 &amp;quot;abcd&amp;quot;) &amp;quot;normal case&amp;quot;)
  (is &amp;quot;ab&amp;quot; (substring 0 2 &amp;quot;abcd&amp;quot;) &amp;quot;normal case substing&amp;quot;)
  (is &amp;quot;bc&amp;quot; (substring 1 3 &amp;quot;abcd&amp;quot;) &amp;quot;normal case substing middle&amp;quot;)
  (is &amp;quot;&amp;quot; (substring 4 4 &amp;quot;abcd&amp;quot;) &amp;quot;normal case&amp;quot;)
  (is &amp;quot;&amp;quot; (substring 0 0 &amp;quot;abcd&amp;quot;) &amp;quot;normal case&amp;quot;)
  (is &amp;quot;d&amp;quot; (substring 3 4 &amp;quot;abcd&amp;quot;) &amp;quot;normal case&amp;quot;)
  (is &amp;quot;abcd&amp;quot; (substring 0 t &amp;quot;abcd&amp;quot;) &amp;quot;end is t&amp;quot;)
  (is &amp;quot;abcd&amp;quot; (substring 0 nil &amp;quot;abcd&amp;quot;) &amp;quot;end is nil&amp;quot;)
  (is &amp;quot;abcd&amp;quot; (substring 0 100 &amp;quot;abcd&amp;quot;) &amp;quot;end is too large&amp;quot;)
  (is &amp;quot;abc&amp;quot; (substring 0 -1 &amp;quot;abcd&amp;quot;) &amp;quot;end is negative&amp;quot;)
  (is &amp;quot;b&amp;quot; (substring 1 -2 &amp;quot;abcd&amp;quot;) &amp;quot;end is negative&amp;quot;)
  (is &amp;quot;&amp;quot; (substring 2 1 &amp;quot;abcd&amp;quot;) &amp;quot;start is bigger than end&amp;quot;)
  (is &amp;quot;&amp;quot; (substring 0 -100 &amp;quot;abcd&amp;quot;) &amp;quot;end is too low&amp;quot;)
  (is &amp;quot;&amp;quot; (substring 100 1 &amp;quot;abcd&amp;quot;) &amp;quot;start is too big&amp;quot;)
  (is &amp;quot;abcd&amp;quot; (substring -100 4 &amp;quot;abcd&amp;quot;) &amp;quot;start is too low&amp;quot;)
  (is &amp;quot;abcd&amp;quot; (substring -100 100 &amp;quot;abcd&amp;quot;) &amp;quot;start and end are too low and big&amp;quot;)
  (is &amp;quot;&amp;quot; (substring 100 -100 &amp;quot;abcd&amp;quot;) &amp;quot;start and end are too big and low&amp;quot;)
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;see-also&#34;&gt;See also&lt;/h3&gt;

&lt;p&gt;and afterwards I saw
&lt;a href=&#34;https://github.com/diogoalexandrefranco/cl-strings&#34;&gt;cl-strings&lt;/a&gt; which
does help but can have its shortcomings.&lt;/p&gt;

&lt;p&gt;The Cookbook is updated: &lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/strings.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/strings.html&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why is there no generic operators ?</title>
      <link>/blog/why-is-there-no-generic-operators/</link>
      <pubDate>Fri, 14 Apr 2017 16:27:44 +0200</pubDate>
      
      <guid>/blog/why-is-there-no-generic-operators/</guid>
      <description>

&lt;p&gt;&lt;em&gt;TLDR;&lt;/em&gt; because the object system came afterwards (and it was not the
 intention to make CL entirely object oriented).&lt;/p&gt;

&lt;p&gt;As a CL enthousiast coming from Python, I feel the pain not to have
generic or polymorphic operators but having to learn about many
specialized operators instead. Why is it so and are there solutions ?&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I &lt;a href=&#34;https://stackoverflow.com/questions/43416293/why-is-there-no-generic-operators-for-common-lisp&#34;&gt;asked&lt;/a&gt; on SO.&lt;/p&gt;

&lt;p&gt;In CL, there are many operators to check for equality that depend on
the data type: &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;string-equal&lt;/code&gt;, &lt;code&gt;char=&lt;/code&gt;, then &lt;code&gt;equal&lt;/code&gt;, &lt;code&gt;eql&lt;/code&gt; and
whatnot, so on for other data types, and the same for comparison
operators. There are no generic and extendible operators. For our
own types, we define its own functions.&lt;/p&gt;

&lt;p&gt;As a reminder for those equality operators: &lt;code&gt;equal&lt;/code&gt; does work on
integers, strings and characters and &lt;code&gt;equalp&lt;/code&gt; also works for lists,
vectors and hash tables an other Common Lisp types but objects. See
&lt;a href=&#34;https://stackoverflow.com/questions/43416293/why-is-there-no-generic-operators-for-common-lisp&#34;&gt;the SO answers&lt;/a&gt;
for precisions and experienced lispers debatting of the inner
subtilities and traps of those functions.&lt;/p&gt;

&lt;p&gt;The language has mechanisms to create generics though, see
&lt;a href=&#34;http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html&#34;&gt;generics (defgeneric, defmethod)&lt;/a&gt;
as described in Practical Common Lisp.&lt;/p&gt;

&lt;p&gt;There have been work in that direction (&lt;a href=&#34;https://common-lisp.net/project/cdr/document/8/cleqcmp.html&#34;&gt;https://common-lisp.net/project/cdr/document/8/cleqcmp.html&lt;/a&gt;) but no library as of today.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a recurrent concern, also
&lt;a href=&#34;https://www.reddit.com/r/programming/comments/65ct5j/a_pythonist_finds_a_new_home_at_clojure_land/&#34;&gt;this blog post&lt;/a&gt;
(&amp;ldquo;Not a monad tutorial&amp;rdquo;, great serie) points to this. The guy moved
to Clojure, for other reasons too of course, where there are only one (or
two?) equality operators.&lt;/p&gt;

&lt;p&gt;So it seems that the reason is mostly historical, the object system
(CLOS) appearing afterwards. Of course the generics would be
slower. But how much slower ? I really don&amp;rsquo;t care, as a beginner and
for web stuff.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generic CLOS functions were added several years after CL was originally designed (82-84). The variant with CLOS was widely published with CLtL2 (1990) and then ANSI CL. The language was only slightly updated. It was not the intention to make Common Lisp fully object oriented. Also performance of CLOS for relatively low-level functions is kind of problematic. Dylan, which is something like Scheme + CLOS - s-expression syntax, did this: it defines more of the language in terms of generic functions. [Rainer Joswig on SO]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;the-cl21-way&#34;&gt;The CL21 way&lt;/h3&gt;

&lt;p&gt;Fortunately &lt;a href=&#34;http://cl21.org/&#34;&gt;CL21&lt;/a&gt; introduces (more) generic
operators, particularly for sequences it defines &lt;code&gt;length&lt;/code&gt;, &lt;code&gt;append&lt;/code&gt;,
&lt;code&gt;setf&lt;/code&gt;, &lt;code&gt;getf&lt;/code&gt;, &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;rest&lt;/code&gt;, &lt;code&gt;subseq&lt;/code&gt;, &lt;code&gt;replace&lt;/code&gt;, &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;,
&lt;code&gt;take-while&lt;/code&gt;, &lt;code&gt;drop-while&lt;/code&gt;, &lt;code&gt;last&lt;/code&gt;, &lt;code&gt;butlast&lt;/code&gt;, &lt;code&gt;find-if&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;,
&lt;code&gt;remove-if&lt;/code&gt;, &lt;code&gt;delete-if&lt;/code&gt;, &lt;code&gt;reverse&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;split&lt;/code&gt;,
&lt;code&gt;join&lt;/code&gt;, &lt;code&gt;remove-duplicates&lt;/code&gt;, &lt;code&gt;every&lt;/code&gt;, &lt;code&gt;some&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;sum&lt;/code&gt; (and some
more). Those should work at least for &lt;strong&gt;strings&lt;/strong&gt;, &lt;strong&gt;lists&lt;/strong&gt;,
&lt;strong&gt;vectors&lt;/strong&gt; and extend the new &lt;code&gt;abstract-sequence&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;Now CL21 is something worth presenting and debatting in another post.&lt;/p&gt;

&lt;p&gt;More:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cl21/cl21/wiki&#34;&gt;https://github.com/cl21/cl21/wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lispcookbook.github.io/cl-cookbook/cl21.html&#34;&gt;https://lispcookbook.github.io/cl-cookbook/cl21.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Example of interactively changing the current executed Lisp code in the debugger</title>
      <link>/blog/example-of-interactively-changing-the-current-executed-lisp-code-in-the-debugger/</link>
      <pubDate>Fri, 14 Apr 2017 13:06:27 +0200</pubDate>
      
      <guid>/blog/example-of-interactively-changing-the-current-executed-lisp-code-in-the-debugger/</guid>
      <description>&lt;p&gt;The awesome example we will read comes from a comment by user lispm
inside a discussion on this reddit thread:
&lt;a href=&#34;https://www.reddit.com/r/programming/comments/65ct5j/a_pythonist_finds_a_new_home_at_clojure_land/&#34;&gt;https://www.reddit.com/r/programming/comments/65ct5j/a_pythonist_finds_a_new_home_at_clojure_land/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The article it discusses is a
&lt;a href=&#34;https://notamonadtutorial.com/a-pythonist-finds-a-new-home-at-clojure-land-761ad8612b47&#34;&gt;&amp;ldquo;Not a monad tutorial&amp;rdquo;&lt;/a&gt;
post, where the interviewee is experienced in C++, Java, Javascript and Python and
turns into Clojure. He wrote about his first impressions with Common
Lisp
&lt;a href=&#34;https://facundoolano.wordpress.com/2012/01/31/first-impressions-on-common-lisp/&#34;&gt;here&lt;/a&gt;,
where he raises usual concerns that I agree with but IMO that stay
supercifial (&amp;ldquo;not readable&amp;rdquo; because of stuff like &lt;code&gt;(format t
&amp;quot;~{~{~a:~10t~a~%~}~%~}&amp;quot; *db*)&lt;/code&gt;, &amp;ldquo;huge operators set&amp;rdquo;, &amp;ldquo;macros look
promising&amp;rdquo;…).&lt;/p&gt;

&lt;p&gt;Here starts the discussion.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;code&gt;dzecniv&lt;/code&gt; On Common Lisp, I agree with the criticisms except&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the code was very difficult to read&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I find it very easy, always well expressed, with concise
functions. And I find Clojure&amp;rsquo;s harder, with more
&lt;code&gt;[&lt;/code&gt;, &lt;code&gt;{&lt;/code&gt; and the same number of other symbols (&lt;code&gt;#&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Anyway, I&amp;rsquo;m in the process of trying to go from python to CL.
The CL ecosystem is quite good nowadays (equivalents of pip, venvs, pyenv, implementations (even
for the JVM or iOS), CI, sphinx, readthedocs, wsgi, setup.py,,…), it&amp;rsquo;s moving, we can do quite a
lot (&lt;a href=&#34;https://github.com/CodyReichert/awesome-cl&#34;&gt;awesome list&lt;/a&gt;),
it has unique features but yeah, the ecosystem is tiny compared to
clojure&amp;rsquo;s…&lt;/p&gt;

&lt;p&gt;ps: interested ? &lt;a href=&#34;http://lisp-lang.org/&#34;&gt;http://lisp-lang.org/&lt;/a&gt; !&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lispm&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tiny compared to clojure&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In many ways is it much broader than Clojure, since there is much more
choice. Interpreters, compilers, native code compilers, batch
compilers, compilers targeting
C/LLVM/JVM/ARM/ARM64/x86/x86-64/SPARC64/POWER/&amp;hellip;&lt;/p&gt;

&lt;p&gt;Clojure on the JVM uses a relatively simple and not very user-friendly
compiler to the JVM. No Interpreter. No mixed use of interpreted and
compiled code. Functions need to be declared before used. Error
messages are exposing the underlying JVM. No TCO. No images. Slow
startup.&lt;/p&gt;

&lt;p&gt;The Roomba cleans your home with a CL program.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MagicMurderBagYT&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No Interpreter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hol up. What about the REPL?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lispm&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s not an interpreter. A REPL is not the same as a Lisp
interpreter. REPL means read eval print loop. EVAL can be implemented
by a compiler or an interpreter. Common Lisp has both and mixed
implementations with both compiler and interpreter.&lt;/p&gt;

&lt;p&gt;A Lisp interpreter is executing Lisp code directly. Clojure does not have an Interpreter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://clojure.org/reference/evaluation&#34;&gt;https://clojure.org/reference/evaluation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clojure has no interpreter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example in LispWorks, which uses the Interpreter in the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER 29 &amp;gt; (let ((f (lambda (a b)
                         (+ (prog1 2 (break))  ; we have a break here
                            (* a b)))))
              (funcall f 2 3))

Break.
  1 (continue) Return from break.
  2 (abort) Return to level 0.
  3 Return to top loop level 0.

Type :b for backtrace or :c &amp;lt;option number&amp;gt; to proceed.
Type :bug-form &amp;quot;&amp;lt;subject&amp;gt;&amp;quot; for a bug report template or :? for other options.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you see Lisp comes with a sub-repl in the break. The sub-repl is
just another repl, but in the context of the break. The break could be
done by the debugger when it sees an error or by user code - as above.&lt;/p&gt;

&lt;p&gt;Now we ask the interpreter for the current lambda expression:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER 30 : 1 &amp;gt; :lambda
(LAMBDA (A B) (+ (PROG1 2 (BREAK)) (* A B)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Above is actually Lisp data. Code as data.&lt;/p&gt;

&lt;p&gt;Now I&amp;rsquo;m changing the + function in the code to be expt,
exponentiation. To be clear: I&amp;rsquo;m changing in the debugger the current
executed Lisp function on the Lisp level. We take the third element of
the list, and then the first one of that. This is the + symbol. We
change it to be expt. * holds the last evaluation result of the REPL.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER 31 : 1 &amp;gt; (setf (first (third *)) &#39;expt)
EXPT
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then I&amp;rsquo;m restarting the current stack frame:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER 32 : 1 &amp;gt; :res
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We get another break, which we just continue from:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Break.
  1 (continue) Return from break.
  2 (abort) Return to level 0.
  3 Return to top loop level 0.

Type :b for backtrace or :c &amp;lt;option number&amp;gt; to proceed.
Type :bug-form &amp;quot;&amp;lt;subject&amp;gt;&amp;quot; for a bug report template or :? for other options.

CL-USER 33 : 1 &amp;gt; :c 1
64                                   ; we computed 2^(2*3)  instead of 2+(2*3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What did we see? We saw that the interpreter uses actual Lisp
code. Lisp code we can change with Lisp code in the debugger.&lt;/p&gt;

&lt;p&gt;A second example.&lt;/p&gt;

&lt;p&gt;What can we do with that for debugging? Well, we can for example write
our own evaluation tracer. The Evaluator prints each expression and
its result nicely indented, while walking the expression tree and
evaluating subexpressions. Remember: this is now user-level code. The
example is from CLtL2. You will also see that LispWorks can freely mix
compiled and interpreted functions. The function COMPILE takes a
function name and compiles its Lisp code to machine code.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;CL-USER 1 &amp;gt; (defvar *hooklevel* 0)
*HOOKLEVEL*

CL-USER 2 &amp;gt; (defun hook (x)
              (let ((*evalhook* &#39;eval-hook-function))
                (eval x)))
HOOK

CL-USER 3 &amp;gt; (compile &#39;hook)
HOOK
NIL
NIL

CL-USER 4 &amp;gt; (defun eval-hook-function (form &amp;amp;rest env)
              (let ((*hooklevel* (+ *hooklevel* 1)))
                (format *trace-output* &amp;quot;~%~V@TForm:  ~S&amp;quot;
                        (* *hooklevel* 2) form)
                (let ((values (multiple-value-list
                               (evalhook form
                                         #&#39;eval-hook-function
                                         nil
                                         env))))
                  (format *trace-output* &amp;quot;~%~V@TValue:~{ ~S~}&amp;quot;
                          (* *hooklevel* 2) values)
                  (values-list values))))
EVAL-HOOK-FUNCTION

CL-USER 5 &amp;gt; (compile &#39;eval-hook-function)
EVAL-HOOK-FUNCTION
NIL
NIL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can trace the evaluation of expressions on the Lisp level:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CL-USER 6 &amp;gt; (hook &#39;(cons (floor *print-base* 2) &#39;b))

  Form:  (CONS (FLOOR *PRINT-BASE* 2) (QUOTE B))
    Form:  (FLOOR *PRINT-BASE* 2)
      Form:  *PRINT-BASE*
      Value: 10
      Form:  2
      Value: 2
    Value: 5 0
    Form:  (QUOTE B)
    Value: B
  Value: (5 . B)
(5 . B)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;dzecniv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;that&amp;rsquo;s an awesome example and tutorial that I&amp;rsquo;d love to see on a blog
post or just a gist or something for further reference and better
archiving, this will be buried too quickly on reddit !&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;So here it is.&lt;/p&gt;

&lt;p&gt;Epilogue: &lt;a href=&#34;https://duckduckgo.com/?q=the+roomba&amp;amp;ia=web&#34;&gt;the Roomba robot vacuums&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>About me</title>
      <link>/about/</link>
      <pubDate>Sun, 05 Feb 2017 07:51:49 +0100</pubDate>
      
      <guid>/about/</guid>
      <description>&lt;p&gt;Hi, it&amp;rsquo;s Vincent. I write about my &lt;strong&gt;Common Lisp journey&lt;/strong&gt; here. I
started the blog when I was discovering the language and the
ecosystem, wishing more people wrote about CL. Because Common Lisp &lt;del&gt;is&lt;/del&gt; was
the most hidden world I know.&lt;/p&gt;

&lt;p&gt;I now wrote tools, libraries and software, I run a web app in
production©, and I am creating &lt;a href=&#34;https://www.youtube.com/channel/UC1l24uzOAt46O7F2NQhA4yw&#34;&gt;videos on Youtube&lt;/a&gt; and &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;a Common Lisp course on Udemy&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I write intensively about Common Lisp &lt;em&gt;on collaborative resources&lt;/em&gt;. &lt;strong&gt;My hidden plan is to make Common Lisp popular again&lt;/strong&gt;. For this, I contribute to the &lt;a href=&#34;https://github.com/LispCookbook/cl-cookbook/&#34;&gt;Common Lisp Cookbook&lt;/a&gt; (I am the main contributor, by far). I wrote about: CLOS, data structures, building executables, scripting, web scraping, debugging, error handling, testing, databases, GUI programming, web development, the LispWorks IDE etc, and I added a theme, a sidebar and syntax highlighting. I also take time to maintain the &lt;a href=&#34;https://github.com/CodyReichert/awesome-cl/&#34;&gt;awesome-cl list&lt;/a&gt;, an important resource in my eyes. I dig up, reference and sort Common Lisp libraries (and I still discover hidden gems &lt;del&gt;three&lt;/del&gt; five years after). I do community stuff for &lt;a href=&#34;https://twitter.com/LispAdvocates&#34;&gt;Lisp Advocates&lt;/a&gt; (not the creator).&lt;/p&gt;

&lt;p&gt;But I still want Common Lisp to be easier to learn. So I am creating this Lisp course in videos:&lt;/p&gt;

&lt;p&gt;🎥 &lt;a href=&#34;https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358&#34;&gt;Common Lisp programming: from novice to effective programmer&lt;/a&gt; (&lt;a href=&#34;https://github.com/vindarel/common-lisp-course-in-videos&#34;&gt;on GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I truly think it is the most effective way to learn CL! I sum up in 5-15 minutes videos what took me a long time to learn or simply discover (a longer time to admit).&lt;/p&gt;

&lt;p&gt;So now a newcomer has far more practical information for getting started than a few years ago. But there&amp;rsquo;s still a lot to do. Besides purchasing or sharing my course, you can thank and encourage me by donations on the following platforms. As I currently don&amp;rsquo;t have a fixed (nor big) income, that helps. Thanks!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub sponsors: &lt;a href=&#34;https://github.com/sponsors/vindarel/&#34;&gt;https://github.com/sponsors/vindarel/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ko-fi: &lt;a href=&#34;https://ko-fi.com/vindarel&#34;&gt;https://ko-fi.com/vindarel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;liberapay: &lt;a href=&#34;https://liberapay.com/vindarel/&#34;&gt;https://liberapay.com/vindarel/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div&gt;
&lt;br/&gt;
&lt;script type=&#39;text/javascript&#39; src=&#39;https://ko-fi.com/widgets/widget_2.js&#39;&gt;&lt;/script&gt;&lt;script type=&#39;text/javascript&#39;&gt;kofiwidget2.init(&#39;Buy me a coffee!&#39;, &#39;#29abe0&#39;, &#39;K3K828W0V&#39;);kofiwidget2.draw();&lt;/script&gt;
&lt;/div&gt;

&lt;p&gt;I also write and maintain tools, libraries, software and project skeletons. Among others:&lt;/p&gt;

&lt;p&gt;libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-str/&#34;&gt;cl-str&lt;/a&gt;, that fixed my first frustration with CL&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ciel-lang/CIEL&#34;&gt;CIEL&lt;/a&gt; - a fast startup scripting environment for Common Lisp, with batteries included. Usable, still in development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/replic/&#34;&gt;replic&lt;/a&gt;, to help create a readline application in no time

&lt;ul&gt;
&lt;li&gt;see how I use it in cl-torrents or in &lt;a href=&#34;https://github.com/vindarel/lyrics-cli&#34;&gt;lyrics-cli&lt;/a&gt;, there is &lt;a href=&#34;https://github.com/vindarel/lyrics-cli/commit/0a75ae78a172b2aba427d2a5911d8034174c43fd#&#34;&gt;one commit&lt;/a&gt; that adds replic support.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/fuzzy-match&#34;&gt;fuzzy-match&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-sendgrid&#34;&gt;cl-sendgrid&lt;/a&gt;, to send emails easily with the Sendgrid API.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/progressons&#34;&gt;progressons&lt;/a&gt; - a progress bar.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-readline&#34;&gt;cl-readline&lt;/a&gt; (maintainer)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-ansi-term&#34;&gt;cl-ansi-term&lt;/a&gt; (maintainer)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/ABStock&#34;&gt;ABStock&lt;/a&gt;, a catalogue of books (and other products)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/OpenBookStore/openbookstore&#34;&gt;OpenBookStore&lt;/a&gt;, a personal book manager, aiming to replace Abelujo&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-torrents&#34;&gt;cl-torrents&lt;/a&gt;, with an experimental &lt;a href=&#34;https://github.com/vindarel/cl-torrents-web&#34;&gt;Weblocks front-end&lt;/a&gt;
&lt;!-- - [Abelujo](https://gitlab.com/vindarel/abelujo/), a free software for bookshops (Python) --&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/colisper&#34;&gt;colisper&lt;/a&gt;, an interface to Comby, for syntactic code checking and refactoring of Lisp code.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/indent-tools&#34;&gt;indent-tools&lt;/a&gt; (emacs package)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/print-licenses&#34;&gt;print-licences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a simple tool to fetch the status of your Gitlab pipelines: &lt;a href=&#34;https://github.com/vindarel/pipelines-viewer&#34;&gt;pipelines-viewer&lt;/a&gt; (just a demo on how to access third-party APIs and how to build a binary, really)
&lt;!-- - [slime-load-this-project](https://github.com/vindarel/slime-load-this-project), an emacs package that wants to ease the … --&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/format-colors&#34;&gt;format-colors&lt;/a&gt;, a set of simple &lt;code&gt;format&lt;/code&gt; directives to print colored text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;project skeletons and demos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/cl-cookieproject&#34;&gt;cl-cookieproject&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;check out this video: 🎥 &lt;a href=&#34;https://github.com/vindarel/cl-cookieproject&#34;&gt;How to create, run, build and load a new Common Lisp project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the companion skeleton for web apps: &lt;a href=&#34;https://github.com/vindarel/cl-cookieweb&#34;&gt;cl-cookieweb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/lisp-web-template-productlist&#34;&gt;lisp-web-template-productlist&lt;/a&gt;: Hunchentoot + easy-routes + Djula templates + Bulma CSS + a Makefile to build the project&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/demo-web-live-reload&#34;&gt;demo-web-live-reload&lt;/a&gt;: an example of how image-based development is useful. Learn to interact with a running website, including with a remote one with Swank.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/demo-ISSR-djula&#34;&gt;demo-ISSR-djula&lt;/a&gt; - a demo on how to build a dynamic web app without JavaScript, but with ISSR, Interactive Server-Side Rendering (and Djula templates).&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vindarel/weblocks-todomvc&#34;&gt;Weblocks-todomvc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/vindarel/lisp-maintainers&#34;&gt;lisp-maintainers&lt;/a&gt; list.&lt;/li&gt;
&lt;li&gt;the funny &lt;a href=&#34;https://github.com/vindarel/Hacker-Typer&#34;&gt;Hacker Typer in Lisp&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/vindarel/list-of-languages-implemented-in-lisp&#34;&gt;list of languages implemented in Lisp&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I contribute to awesome projects such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/40ants/weblocks/&#34;&gt;Weblocks&lt;/a&gt;, an &lt;a href=&#34;https://github.com/vindarel/awesome-no-js-web-frameworks&#34;&gt;isomorphic web framework&lt;/a&gt;. I helped write the quickstart, fixed HTML generation in tables, wrote more documentation, raised issues.&lt;/li&gt;
&lt;li&gt;the &lt;a href=&#34;https://github.com/atlas-engineer/nyxt/&#34;&gt;Nyxt browser&lt;/a&gt;: I was part of the team in 2019, I am the second contributor of that year.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and I fix bugs when I see them (Mito (&lt;a href=&#34;https://github.com/fukamachi/mito/graphs/contributors&#34;&gt;my contributions!&lt;/a&gt;), Djula…).&lt;/p&gt;

&lt;p&gt;You can reach me by email at vindarel, mailz dot org. I am &lt;a href=&#34;https://www.reddit.com/user/dzecniv/&#34;&gt;/u/(reverse (str:concat &amp;ldquo;vince&amp;rdquo; &amp;ldquo;zd&amp;rdquo;))&lt;/a&gt; on reddit.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This website&amp;rsquo;s sources are on Gitlab: &lt;a href=&#34;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/issues&#34;&gt;https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/issues&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
