In: lisp, programming, language.
Common LISP (programming language)
Lisp is the second-oldest high-level programming language after Fortran and has changed a great deal since its early days, and a number of dialects have existed over its history. Today, the most widely known general-purpose Lisp dialects are Common Lisp and Scheme.
Lisp was invented by John McCarthy in 1958 while he was at the Massachusetts Institute of Technology (MIT).
Wiki
- https://wikipedia.org/wiki/Common_Lisp
- https://wikipedia.org/wiki/Steel_Bank_Common_Lisp
- https://wikipedia.org/wiki/Clozure_CL
Awesome
Hyperpolyglot
Implementations
- https://sbcl.org – Steel Bank Common Lisp
- https://ccl.clozure.com – Clozure Common Lisp CCL
- https://gnu.org/software/clisp – GNU CLISP, an ANSI Common Lisp Implementation
- https://ecl.common-lisp.dev – Embeddable Common-Lisp ECL
- https://github.com/clasp-developers/clasp – Common Lisp and C++ together
Tools
- https://github.com/joaotavora/sly – Sylvester the Cat’s Common Lisp IDE
- https://slime.common-lisp.dev – SLIME: The Superior Lisp interaction mode for Emacs
- https://portacle.github.io – a complete IDE for Common Lisp that you can take with you on a USB stick
- https://quicklisp.org – library manager for Common Lisp
- https://roswell.github.io – environment setup utility
- https://ultralisp.org – a fast-moving Common Lisp software distribution
- https://github.com/jscl-project/jscl – Common-LISP-to-Javascript compiler
Useful libraries:
- https://github.com/vseloved/rutils – radical utilities for Common Lisp
- https://github.com/ruricolist/serapeum – a conservative library of Common Lisp utilities
- https://alexandria.common-lisp.dev – a collection of portable public domain utilities
Generative art:
- https://github.com/inconvergent/weird – lots of Github stars! Generative art utils
weird is the next iteration of weir, which was the next iteration of snek - https://github.com/vydd/sketch – creation of electronic art, visual design, game prototyping, game making, computer graphics, exploration of human-computer interaction
- https://github.com/slyrus/opticl – representing and processing images in Common Lisp
Learn
- https://articulate-lisp.com – Articulate Common Lisp
- https://cliki.net
- https://cs.cmu.edu/~dst/LispBook – Gentle intro
- https://dept-info.labri.fr/~strandh/Teaching/MTP/Common/David-Lamkins/contents.html – Book: Successful Lisp by David B. Lamkins
- https://learnxinyminutes.com/docs/common-lisp
- https://lispcookbook.github.io/cl-cookbook – The Common Lisp cookbook
- https://lisp-lang.org/learn – Simple and short Common LISP intro
- https://paulgraham.com/acl.html – Book: ANSI Common LISP by Paul Graham
- https://paulgraham.com/onlisp.html – Book: On LISP by Paul Graham
- https://rosettacode.org/wiki/Category:Common\_Lisp – Common Lisp examples
- https://tutorialspoint.com/lisp
Video
- https://youtube.com/watch?v=M-BFgErib4k – O’Reilly, Brief introduction to LISP - Pt 1, Syntax
- https://youtube.com/watch?v=jvnwXHsL8eo – O’Reilly, Brief Introduction to LISP - Pt 2, Functions
- https://youtube.com/watch?v=xfh-oXjS73I – O’Reilly, Brief Introduction to LISP - Pt 3, Scoping
- https://youtube.com/watch?v=g\_RjV5Q3sTY – O’Reilly, Brief Introduction to LISP - Pt 4, Lists
NOTES
Numbers
(+ 1 2) ;; => 3
#xFF ;; => 255
;; base 16
#16rFF ;; => 255
#16r10 ;; => 16
;; base 32
#32r10 ;; => 32
;; For numbers, use =
(= 5 5.0) ;; => T
(eq 5 5.0) ;; => NIL
(eql 5 5.0) ;; => NIL
(type-of 10) ;; => (INTEGER 0 ...)
(type-of 1.5) ;; => SINGLE-FLOAT
(type-of -5) ;; => FIXNUM
(abs -3) ;; => 3
(float 1) ;; => 1.0
(ceiling 1.45) ;; => 2
(floor 1.45) ;; => 1
(round 1.45) ;; => 1
(ffloor 2.5) ;; => 2.0 0.5
(fround 2.5) ;; => 2.0 0.5
(ftruncate 2.5) ;; => 2.0 0.5
(rem -10 3) ;; => -1
(mod -10 3) ;; => 2
(max 1 2 3) ;; => 3
(min 1 2 3) ;; => 1
;; a random nr from 0 up-to 100
(random 100)
;; increment INCF
(let ((x 1)) (incf x)) ;; => 2
;; decrement DECF
(let ((x 1)) (decf x)) ;; => 0
most-positive-fixnum ;; => 4611686018427387903
most-negative-fixnum ;; => -4611686018427387904
- http://clhs.lisp.se/Body/f_floorc.htm
- http://clhs.lisp.se/Body/f_mod_r.htm
- https://tutorialspoint.com/lisp/lisp_numbers.htm
- https://lispcookbook.github.io/cl-cookbook/numbers.html
- http://cs.cmu.edu/Groups/AI/html/cltl/clm/node121.html
Cons pairs & Lists
A cons cell, also known as a dotted pair, is simply a pair of two objects.
Common Lisp, and other languages in the LISP family, make extensive use of lists, but Common Lisp doesn’t actually include a primitive list datatype.
The lists exist only by convention.
;; to create a CONS pair
(cons 1 2) ;; => (1 . 2)
;; can also be expressed as
'(1 . 2) ;; => (1 . 2)
(type-of (cons 1 2)) ;; => CONS
;; a nested cons pair
(cons 1 (cons 2 3))
;; => (1 2 . 3)
;; this is now a list, by convention
(cons 1 (cons 2 nil)) ;; => (1 2)
;; shorter way of declaring a list
(list 1 2) ;; => (1 2)
;; and even shorter
'(1 2) ;; => (1 2)
;; equivalent with
(quote (1 2)) ;; => (1 2)
;; for lists, strings, and bit-vectors use EQUAL
(equal '(1 2) '(1 2))
To access cons and lists, you have a ton of functions, which is expected for a LISt Processor language:
(car '(1 . 2)) ;; => 1
(car '(1 2)) ;; => 1
(cdr '(1 . 2)) ;; => 2
(cdr '(1 2)) ;; => (2)
(cdr '(1 2 3)) ;; => (2 3)
(rest '(1 2 3)) ;; => (2 3)
;; prettier names
(first '(1 2)) ;; => 1
(last '(1 2)) ;; => (2)
(butlast '(1 2 3)) ;; => (1 2)
;; also: first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth
;; first is functionally equivalent to car, second is functionally equivalent to cadr, third is functionally equivalent to caddr, and fourth is functionally equivalent to cadddr
(setq li '(1 2 3 4))
(second li) ;; => 2
(third li) ;; => 3
(fourth li) ;; => 4
;; check if variable is a list
(listp li)
;; the length of a list
(list-length li)
;; the tail of list beginning with the first matching element
(member 4 '(1 2 3 4 5)) ;; => (4 5)
;; Sequence func: count how many times is found
(count 3 '(1 3 3 3 3)) ;; => 4
;; copy a list
(copy-list li)
Changing lists:
;; concatenate lists
(append (list 1 2) (list 3 4)) ;; => (1 2 3 4)
;; also
(concatenate 'list '(1 2) '(3 4)) ;; => (1 2 3 4)
(defparameter list1 '(1 2 3))
(push 0 list1) ;; => (0 1 2 3)
(pop list1) ;; => (1 2 3)
;; insert fist and return new list
(list\* 0 list1)
;; => (0 1 2 3)
;; reverse a list
(reverse list1)
;; => (3 2 1)
- https://m.wikipedia.org/wiki/CAR_and_CDR
- https://riptutorial.com/common-lisp/example/8701/what-is-a-cons-cell
- https://riptutorial.com/common-lisp/example/8700/lists-as-a-convention
- http://lispworks.com/documentation/HyperSpec/Body/f\_firstc.htm
- http://cs.cmu.edu/Groups/AI/html/cltl/clm/node149.html
- https://lispcookbook.github.io/cl-cookbook/data-structures.html
- https://sodocumentation.net/common-lisp/topic/2622/cons-cells-and-lists
- https://sodocumentation.net/common-lisp/topic/3744/types-of-lists
- https://lisp-lang.org/learn/lists
Property Lists (Plists)
By convention, you can define lists that represent kind of key to value mappings.
A property list, or Plist, is a regular list in which alternating values are interpreted as keys and their associated values.
;; define an object with 3 keys and 3 values
(defparameter *3dobj* (list 'x 10 'y 5 'z 25))
;; get value of X
(getf *3dobj* 'x)
;; get and use default
(getf *3dobj* 'wrong -1)
;; set new value of X
(setf (getf *3dobj* 'x) 15)
;; create new plist with extra keys-values
(defvar *new-3dobj* (list* 'j -1 *3dobj*))
Association Lists (ALists)
By convention, you can define lists that represent kind of key to value mappings.
An association list, or alist is a regular list whose elements are dotted pairs in which the car of each pair is the key and the cdr of each pair is the associated value.
;; define an object with 3 keys and 3 values
(defparameter \*3dobj\* (list (cons 'x 10) (cons 'y 5) (cons 'z 25)))
;; ZIP keys and values
(pairlis '(a b c) '(2 4 8))
;; => ((C . 8) (B . 4) (A . 2))
;; get a key-value pair
(car (member 'z \*3dobj\* :key 'car)) ;; => (z . 25)
;; shorter
(assoc 'y \*3dobj\*) ;; => (y . 5)
;; create new alist with extra keys-values
(acons 'c 3 '((a . 1) (b . 2)))
;; => ((c . 3) (a . 1) (b . 2))
- http://lispworks.com/documentation/HyperSpec/Body/f_assocc.htm
- https://riptutorial.com/common-lisp/example/12947/association-lists
Strings
(write "Hello")
(print "Hello")
(char "a-b_c" 0) ;; => #\a
(char "a-b_c" 1) ;; => #\-
(char "a-b_c" 3) ;; => #\_
(length "Hello") ;; => 5
(stringp "a") ;; => T
(type-of "abc") ;; => (SIMPLE-ARRAY CHARACTER (3))
;; convert to string
(string 'tick) ;; => "TICK"
(string #\c) ;; => "c"
(equal "a" "a") ;; => T
(string= "x" "y") ;; => NIL
(string= "A" "a") ;; => NIL
;; string NOT equal
(string/= "" "") ;; => NIL
(string< "a" "b") ;; => 0 means True
(string> "b" "a") ;; => 0 means True
(string> "a" "a") ;; => NIL
(string>= "a" "a") ;; => 1
(string<= "a" "a") ;; => 1
(string-upcase "hey") ;; => HEY
(string-downcase "Hey") ;; => hey
(string-capitalize "hEy") ;; => Hey
(string-trim " " " spaces ")
;; => "spaces"
(string-trim " ,;" " spaces, ; ")
;; => "spaces"
(subseq "Red green blue" 0 9) ;; => "Red green"
(subseq "Red green blue" 10) ;; => "blue"
;; split using regex
(cl-ppcre:split "\." "127.0.0.1")
;; => ("127" "0" "0" "1")
(reverse "Hello") ;; => "olleH"
(concatenate 'string "Hello" "World" "!")
;; => "HelloWorld!"
(sort (vector "C" "A" "b" "abc" "Xyz") #'string<))
;; => #("A" "C" "Xyz" "abc" "b")
- http://clhs.lisp.se/Body/f_char_.htm
- https://tutorialspoint.com/lisp/lisp_strings.htm
- https://lispcookbook.github.io/cl-cookbook/strings.html
- https://gigamonkeys.com/book/numbers-characters-and-strings.html
- https://riptutorial.com/common-lisp/topic/1454/sequence---how-to-split-a-sequence
Format
Format deserves its own special place, because it’s power and super complicated.
- https://gigamonkeys.com/book/a-few-format-recipes.html
- https://lispcookbook.github.io/cl-cookbook/strings.html#with-the-format-function
Variables & Constants
;; local variables
(let ((x 1) (y 2)) (format nil "~a ~a" x y) )
;; a global (dynamically scoped) variable
;; DEFPARAMETER is a macro which uses SETF and always sets a value
;; by convention, global variables have earmuffs
(defparameter \*number\* 5 "optional docstring")
;; DEFVAR is a macro which uses SETF and doesn't overwrite an already existing value
;; you can use it to define default values, if they don't exist
;; the name comes from "define variable"
(defvar n 1)
(defvar n 2)
(print n) ;; => 1
;; SETF is a macro which uses SETQ internally and is more powerful than SETQ
;; SETF is the most general way of setting values
(defparameter li (list 1 2 3))
(setf (car li) 9)
(car li) ;; => 9
;; SETQ can only define simple values
(setq a 1 b 2 c 3)
(setq 3d '(x y z))
;; SETQ always quotes its first argument, for unquoted, use SET
;; SET is considered deprecated
(set 'name "Lisp")
;; Constants are defined with DEFCONSTANT
(defconstant server-addr "localhost:8000" "A server host:port")
(documentation 'server-addr 'variable) ;; => "A server host:port"
(constantp server-addr) ;; => true
- https://stackoverflow.com/questions/8927741/whats-difference-between-defvar-defparameter-setf-and-setq
- https://dept-info.labri.fr/~strandh/Teaching/MTP/Common/David-Lamkins/chapter03-06.html
- https://gigamonkeys.com/book/variables.html
- https://lisp-lang.org/learn/variables
- http://clhs.lisp.se/Body/f_set.htm
- http://clhs.lisp.se/Body/m_defcon.htm
- http://clhs.lisp.se/Body/m_defpar.htm
- http://clhs.lisp.se/Body/s_setq.htm
- http://lispworks.com/documentation/HyperSpec/Body/m_setf_.htm
- http://lispworks.com/documentation/HyperSpec/Body/s_let_l.htm
- http://lispworks.com/documentation/HyperSpec/Body/s_setq.htm
Functions & Lambdas
;; a function without params
(defun hello-world ()
"A function that prints & returns Hello."
(print "Hello World"))
(hello-world) ;; => Hello World
(defun hello (name)
"Say hello to Name."
(format t "Hello ~a !~&" name))
(hello "Dude") ;; => Hello Dude !
(defun fib (n)
"Return the nth Fibonacci number."
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2)))))
;; call the function like usual
(fib 9) ;; => 34
;; functions can be called programatically
(funcall #'fib 9)
(apply #'fib '(9))
;; #' is a shorthand for (function ...)
(funcall (function +) 1 2)
(apply (function +) '(1 2))
;; simple lambda
(lambda (x) (print x))
- http://cl-cookbook.sourceforge.net/functions.html
- https://lisp-lang.org/learn/functions
- https://gigamonkeys.com/book/functions.html
- https://letoverlambda.com/index.cl/guest/chap2.html
- https://lispcookbook.github.io/cl-cookbook/functions.html
- https://riptutorial.com/common-lisp/example/6982/function-without-parameters
- https://riptutorial.com/common-lisp/example/6980/required-parameters
- https://riptutorial.com/common-lisp/example/6984/auxiliary-variables
- https://riptutorial.com/common-lisp/example/6986/keyword-parameters
- https://riptutorial.com/common-lisp/example/6981/optional-parameters
- https://riptutorial.com/common-lisp/example/6983/rest-parameter
Conditionals
(= 1 1) ;; => T
(eql NIL '()) ;; => T
(and T T) ;; => T
(and T nil) ;; => NIL
(or T T) ;; => T
(or T nil) ;; => T
;; IF condition do else
(if T (print "This is True") (print "This is False"))
;; => "This is True"
;; WHEN and UNLESS don't have an ELSE
(when t 'hello) ;; => HELLO
(unless t 'hello) ;; => NIL
(when nil 'hello) ;; => NIL
(unless nil 'hello) ;;=> HELLO
;; cond macro
(cond ((= a 1) (print 1))
((= a 2) (print 2))
(t 'bigger)) ;; => 1
;; case / switch
(case 1
((1) 'is1)
((2) 'is2)
(otherwise 'bigger)) ;; => IS1
;; switch on the type of the value
(typecase 1
(string "It's a string")
(integer "It's an int")) ;; => It's an int
- http://clhs.lisp.se/Body/c_data_a.htm
- http://clhs.lisp.se/Body/m_when_.htm
- http://clhs.lisp.se/Body/m_case_.htm
- http://clhs.lisp.se/Body/m_cond.htm
- https://riptutorial.com/common-lisp/example/11082/conditional-constructs
- https://tutorialspoint.com/lisp/lisp_decisions.htm
- https://tutorialspoint.com/lisp/lisp_cond_construct.htm
- https://tutorialspoint.com/lisp/lisp_case_construct.htm