Lisp: Common Lisp, Scheme, Clojure, Emacs Lisp

a side-by-side reference sheet

ten primitives | arithmetic and logic | strings | lists | other containers | functions and scope | execution control
environment and i/o | libraries and modules | objects | macros | java interop | contact

common lisp (1984) scheme (1975) clojure (2007) emacs lisp (1985)
version used SBCL 1.0.48 Racket 5.1 Clojure 1.2 Emacs 23.1
version $ sbcl --version
$ clisp --version
$ racket --version
$ csi -v
displayed by repl on startup $ emacs --version
repl $ sbcl
$ clisp
$ racket
$ csi
$ java -jar /PATH/TO/clojure.jar M-x ieml
running in emacs M-x slime none M-x lisp-interaction-mode
shebang #!/usr/bin/env sbcl --script
#!/usr/bin/env clisp
#!/usr/bin/env racket --script specify full path to clojure jar:
#!/usr/bin/env java -jar clojure.jar
#!/usr/local/bin/emacs --script
compiling $ clisp -c file.lisp
$ clisp file
$ mzc module.rkt M-x byte-compile-file
making a standalone executable (sb-ext:save-lisp-and-die
  "executable"
  :executable t
  :toplevel 'function)
$ mzc —exe executable file see note
cell types
 
value, function, struct, class, … value value value, function, struct, …
case sensitive
 
no yes yes yes
argument separator whitespace whitespace whitespace and commas whitespace
nil, is () null?, is () symbol? nil, yes, yes null, yes, no nil, no, no nil, yes, yes
type-of
 
type-of none type class type-of
type predicates null symbolp atom consp listp numberp characterp stringp null? symbol? none pair? list? number? char? string?
racket: cons? synonym for pair?
nil? symbol? none none list? number? none string? null symbolp atom consp listp numberp characterp stringp
set property
 
(setf (get 'foo :prop) 13) none (def foo (with-meta 'x { :prop 13 })) (setf (get 'foo :prop) 13)
get property
 
(get 'foo :prop) none (get (meta foo) :prop) (get 'foo :prop)
remove property (remprop 'foo :prop) none none (remprop 'foo :prop)
quoted symbol 'foo
(quote foo)
'foo
(quote foo)
'foo
(quote foo)
'foo
(quote foo)
special reader characters whitespace ( ) " , ' ` : ; # | \
reserved for user macros:
? ! [ ] { }
whitespace ( ) [ ] { } " , ' ` ; # | \ all except alphanumerics and these:
* + ! - _ ?
these have special meaning or are reserved:
/ . :
whitespace ( ) " , ' ` ; # | \ _ [ ]
escaping special reader characters (setq white\ space\ symbol 3)
(setq |white space symbol| 3)
racket and chicken:
(define |white space symbol| 3)
racket:
(define white\ space\ symbol 3)
none (setq white\ space\ symbol 3)
keyword
 
:foo #:foo :foo :foo
comment (+ 1 1) ; adding
 
(+ 1 #| adding |# 1)
(+ 1 1) ; adding
r6rs:
(+ 1 #| adding |# 1)
(+ 1 1) ; adding (+ 1 1) ; adding
ten primitives
common lisp scheme clojure emacs lisp
atom
 
(atom x) (not (pair? x)) (not (list? x)) (atom x)
quote
 
quote quote quote quote
eq, equal, = eq, equal, = eq?, equal?, = = works on symbols and is true for lists with identical members eq, equal, =
car
 
car, first car racket: car, first first car
cdr
 
cdr, rest cdr racket: cdr, rest rest, next cdr
cons
 
cons cons cons 2nd arg must be a list cons
cond (cond ((> x 0) 1)
  ((= x 0) 0)
  (t -1))
(cond ((> x 0) 1)
  ((= x 0) 0)
  (else -1))
(cond (> x 0) 1
  (= x 0) 0
  true -1)
(cond ((> x 0) 1)
  ((= x 0) 0)
  (t -1))
lambda (lambda (x) (* x x)) (lambda (x) (* x x)) #(* % %)
(fn [x] (* x x))
(lambda (x) (* x x))
label
 
set,setq,defun define def,defn set,setq,defun
apply ((lambda (x) (* x x)) 2)
 
(apply #'(lambda (x) (* x x)) '(2))
((lambda (x) (* x x)) 2)
 
(apply (lambda (x) (* x x)) '(2))
(#(* % %) 2)
 
((fn [x] (* x x)) 2)
 
(apply #(* % %) '(2))
((lambda (x) (* x x)) 2)
 
(apply
  #'(lambda (x) (* x x))
  '(2))
arithmetic and logic
common lisp scheme clojure emacs lisp
falsehoods nil () #f
racket: #f false
false nil nil ()
true, is true symbol? t, yes #t, no
racket: #t true, no
true, no t, yes
logical operators (or (not t) (and t nil)) (or (not #t) (and #t #f)) (or (not true) (and true false)) (or (not t) (and t nil))
numeric predicates numberp integerp
rationalp floatp
realp complexp
number? integer?
rational? inexact?
real? complex?
number? integer?
rational? float?
none none
numberp integerp
none floatp
none none
largest postive integer none none none on 32 bit systems: 228 - 1
on 64 bit systems: 260 - 1
closure of integers under division rationals rationals rationals integers
arithmetic operators + - * / mod expt log + - * / modulo expt log + - * / mod Math/pow Math/log + - * / mod expt log
relational operators = /= < > <= >= = none < > <= >= = none < > <= >= = /= < > <= >=
other functions min max sin cos tan asin acos atan min max sin cos tan asin acos atan min max Math/sin Math/cos Math/tan Math/asin Math/acos Math/atan min max sin cos tan asin acos atan
arithmetic truncation return two values, first is integer:
truncate round ceiling floor
return floats:
truncate round ceiling floor
return integers:
int Math/round
return floats:
Math/ceil Math/floor
truncate round ceiling floor
fround fceiling ffloor
truncate returns integer
convert from string, to string (+ 7 (parse-integer "12"))
 
(+ 73.9 (read-from-string ".037"))
 
(concatenate 'string
  "value: "
  (princ-to-string 8))
(+ 7 (string->number "12"))
 
(+ 73.9 (string->number ".037"))
 
(string-append
  "value: "
  (number->string 8))
(+ 7 (Integer/parseInt "12"))
 
(+ 73.9 (Float/parseFloat ".037"))
 
(str "Value: " 8)
(+ 7 (string-to-number "12"))
 
(+ 73.9
  (string-to-number ".037"))
 
(concat
  "value: "
  (number-to-string 8))
bitwise operators ash left shift when 2nd argument positive logand logior logxor lognot arithmetic-shift left shift when 2nd argument positive bitwise-and bitwise-ior bitwise-xor bitwise-not bit-shift-left bit-shift-right bit-and bit-or bit-xor bit-not lsh left shift when 2nd argument positive logand logior logxor lognot
quotient and remainder (truncate 7 3)
(rem 7 3)
(quotient 7 3)
(remainder 7 3)
(quot 7 3)
(rem 7 3)
(/ 7 3)
(% 7 3)
(sqrt -2) #C(0.0 1.4142135) gambit:
+1.4142135623730951i
chicken:
+nan
racket:
0+1.4142135623730951i
(Math/sqrt -2): NaN -0.0e+NaN
decomposition of integer, rational, complex abs signum numerator denominator realpart imagpart abs sgn numerator denominator real-part imag-part
sgn in racket only
(Math/abs x)
(Math/round (Math/signum (* x 1.0)))
(.numerator x)
(.denominator x)
none
none
abs signum none none none none
random integer, uniform float, normal float (random 100)
(random 1.0)
none
gambit and srfi 27:
(random-integer 100)
(random-real)
none
 
racket:
(random 100)
(random)
none
(def rnd (java.util.Random.))
(.nextInt rnd 100)
(.nextFloat rnd)
(.nextGaussian rnd)
(random 100)
none
none
strings
common lisp scheme clojure emacs lisp
character literals #\a #\Space #\Newline #\Backspace #\Tab #\Linefeed #\Page #\Return #\Rubout #\a #\space #\newline #\backspace #\tab #\linefeed #\page #\return #\nul #\vtab #\alarm #\esc #\delete
not in racket: #\alarm #\esc #\delete
\a \newline \space \backspace \tab ? \formfeed \return ? ?a ?\b ?\t ?\n ?\f ?\r ?\" ?\\ ?\ooo ?\uhhhh ?\xh - ?\xhhhhhh ?\C-x ?\M-x
string literal
 
"foo bar" "foo bar" "foo bar" "foo bar"
string escapes \" \\ \t \n \r \" \\ \ooo \uhhhh \b \t \n \f \r \" \\ \ooo \uhhhh \b \t \n \f \r \" \\ \ooo \uhhhh \xh - \xhhhhhh \C-x \M-x
character access (char "foo" 0) (string-ref "foo" 0) (.charAt "foo" 0) (aref "foo" 0)
find substring (search "bar" "foo bar") racket:
(require srfi/13/string)
(string-contains "foo bar" "bar")
(.indexOf "foo bar" "bar") (search "bar" "foo bar")
extract substring (subseq "foo bar" 4 7) (substring "foo bar" 4 7) (.substring "foo bar" 4 7) (substring "foo bar" 4 7)
length
 
(length "foo") (string-length "foo") (.length "foo") (length "foo")
constructors (make-string 3 :initial-element #\f)
 
(reduce (lambda (m o)
    (concatenate 'string m
      (string o)))
  '(#\f #\o #\o)
  :initial-value "")
(make-string 3 #\f)
 
(string #\f #\o #\o)
(String. (into-array
  (. Character TYPE)
  (repeat 3 \f)))
 
(String. (into-array
  (. Character TYPE)
  '(\f \o \o)))
(make-string 3 ?f)
 
(string ?f ?o ?o)
comparison (string= "foo" "bar")
(string< "foo" "bar")
(string=? "foo" "bar")
(string<? "foo" "bar")
(.equals "foo" "bar")
(.compareTo "foo" "bar")
(string= "foo" "bar")
(string< "foo" "bar")
case (string-downcase "FOO")
(string-upcase "foo")
(string-capitalize "foo")
(string-downcase "FOO") (.toLowerCase "FOO") (downcase "FOO")
(upcase "foo")
(capitalize "foo")
trim (string-trim
  '(#\Space #\Tab #\Newline)
  " foo ")
(require srfi/13/string)
(string-trim-both " foo ")
(.trim " foo ") none; see notes for an implementation
concat (concatenate 'string
  "foo "
  "bar "
  "baz")
(string-append
  "foo "
  "bar "
  "baz")
(str "foo " "bar " "baz") (concat "foo " "bar " "baz")
split (cl-ppcre:split
  "[ \t\n]+"
  "foo bar baz")
(regexp-split #rx"[ \n\t]+"
  "foo bar baz")
(seq
  (.split "foo bar baz"
    "[ \t\n]+"))
(split-string "foo bar baz")
join (reduce
  (lambda (m o)
    (concatenate 'string m " " o))
  '("foo" "bar" "baz"))
(string-join
  '("foo" "bar" "baz")
  " ")
(reduce #(str %1 " " %2)
  '("foo" "bar" "baz"))
(reduce
  (lambda (m o) (concat m " " o))
  '("foo" "bar" "baz"))
format (format nil "~a: ~a ~,2F"
  "Foo"
  7
  13.457)
(format "~a ~a ~a" "Foo" 7 13.457) (String/format "%s: %d %.2f"
  (to-array ["Foo" 7 13.457]))
(format "%s: %d %.2f"
  "Foo"
  7
  13.457)
regular expressions (cl-ppcre:all-matches
  "bar"
  "foo bar")
(regexp-match #rx"bar" "foo bar") (re-seq #"bar" "foo bar") (string-match "bar" "foo bar")
regex substitution (cl-ppcre:regex-replace "[^l]l"
  "hello"
  "EL")
 
(cl-ppcre:regex-replace-all "[^l]l"
  "hello hello"
  "EL")
(regexp-replace #rx"el"
  "hello"
  "EL")
 
(regexp-replace* #rx"el"
  "hello hello"
  "EL")
(.replaceFirst "hello" "[^l]l" "XX")
 
(.replaceAll "hello hello"
  "[^l]l" "XX")
?
 
(replace-regexp-in-string "[^l]l"
  "EL"
  "hello hello")
regex special characters (cl-ppcre:all-matches
  "^[0-9a-f]+$"
  "1ab7")
 
(cl-ppcre:all-matches
  "(\\d\\w\\s)\\1"
  "8a 8a ")
(regexp-match #rx"^[a-f0-9]+$"
  "1ab7")
 
(regexp-match #px"(\\d\\w\\s)\\1"
  "8a 8a ")
(re-seq #"^[0-9a-f]+$" "1ab7")
 
(re-seq #"(\d\w\s)\1" "8a 8a ")
(string-match
  "^[0-9a-f]+$"
  "1abf")
lists
common lisp scheme clojure emacs lisp
list literal
 
'(1 2 3) '(1 2 3) or '[1 2 3] or '{1 2 3} '(1 2 3) '(1 2 3)
pair literal
 
'(1 . 2) '(1 . 2) none '(1 . 2)
(car '())
 
nil error first: nil nil
(cdr '()) nil error rest: ()
next: nil
nil
(eval '())
 
nil error () nil
list functions
 
list listp length append reverse list list? length append reverse list list? count concat reverse list listp length append reverse
nth
 
(nth 3 '(0 1 2 3)) (list-ref '(0 1 2 3) 3) (nth '(0 1 2 3) 3) (nth 3 '(0 1 2 3))
index of list element (position 7 '(5 6 7 8)) srfi-1:
(list-index
  (lambda (x) (= x 7))
  '(5 6 7 8))
none (position 7 '(5 6 7 8))
last butlast (setq a '(1 2 3))
(car (last a))
(butlast a)
racket:
(define a '(1 2 3))
(last a)
(take a (- (length a) 1))
(def a '(1 2 3))
(last a)
(butlast a)
(car (last a))
(butlast a)
set-car set-cdr (setq a '(1 2 3))
(setf (car a) 3)
(setf (cdr a) '(4 5 6))
r5rs only:
(define a '(1 2 3))
(set-car! a 3)
(set-cdr! a '(4 5 6))
none (setq a '(1 2 3)
(setcar a 3)
(setcdr a '(4 5 6))
sort
 
(sort '(3 2 4 1) '<) (sort '(3 2 4 1) <) (sort < '(3 2 4 1)) (sort '(3 2 4 1) '<))
assoc
 
(assoc 3 '((1 2) (3 4))) (assoc 3 '((1 2) (3 4))) none, see note (assoc 3 '((1 2) (3 4))
getf
 
(getf '(1 2 3 4) 3) none none (getf '(1 2 3 4) 3)
map (mapcar
  (lambda (x) (* x x))
  '(1 2 3))
(map (lambda (x) (* x x)) '(1 2 3)) (map #(* % %) '(1 2 3)) (mapcar
  (lambda (x) (* x x))
  '(1 2 3))
filter (remove-if-not
  (lambda (x) (> x 2))
  '(1 2 3))
remove-if returns complement
racket and srfi-1:
(filter
  (lambda (x) (> x 2))
  '(1 2 3))
filter-not returns complement
(filter #(> % 2) '(1 2 3))
remove returns complement
(remove-if-not
  (lambda (x) (> x 2))
  '(1 2 3))
remove-if returns complement
reduce (left fold) (reduce '-
  '(1 2 3 4)
  :initial-value 0)
srfi-1:
(fold - 0 '(1 2 3 4))
racket:
(foldl - 0 '(1 2 3 4))
(reduce - 0 '(1 2 3 4)) (reduce '-
  '(1 2 3 4)
  :initial-value 0)
right fold (reduce '-
  '(1 2 3 4)
  :initial-value 0
  :from-end t)
srfi-1:
(fold-right - 0 '(1 2 3 4))
racket:
(foldr - 0 '(1 2 3 4))
none (reduce '-
  '(1 2 3 4)
  :initial-value 0
  :from-end t)
dolist (dolist (x '(1 2 3))
  (print x)
  (print (- x)))
racket:
(for ((x '(1 2 3)))
  (printf "~a~n" x)
  (printf "~a~n" (- x)))
(doseq [x '(1 2 3)]
  (println x)
  (println (- x)))
(dolist (x '(1 2 3))
  (print x)
  (print (- x)))
universal predicate (every
  (lambda (i) (= 0 (rem i 2)))
  '(1 2 3 4))
racket:
(for/and ((i '(1 2 3 4)))
  (= 0 (remainder i 2)))
(every? #(= 0 (rem % 2)) '(1 2 3 4)) (every
  (lambda (i) (= 0 (% i 2)))
  '(1 2 3 4))
existential predicate (some
  (lambda (i) (= 0 (rem i 2)))
  '(1 2 3 4))
racket:
(for/or ((i '(1 2 3 4)))
  (= 0 (remainder i 2)))
(some #(= 0 (rem % 2)) '(1 2 3 4)) (some
  (lambda (i) (= 0 (% i 2)))
  '(1 2 3 4))
take none racket and srfi-1:
(take '(1 2 3 4) 2)
(take 2 '(1 2 3 4)) none
drop (nthcdr 2 '(1 2 3 4)) racket and srfi-1:
(drop '(1 2 3 4) 2)
(drop 2 '(1 2 3 4)) (nthcdr 2 '(1 2 3 4))
push and pop (setq x '(1 2 3))
(push 4 x)
(pop x)
none (def x '(1 2 3)
none
(pop x)
(setq x '(1 2 3))
(push 4 x)
(pop x)
other containers
common lisp scheme clojure emacs lisp
vector literal
 
#(1 2 3) #(1 2 3) [1 2 3] [1 2 3]
vector access (elt #(1 2 3) 0) or
(aref #(1 2 3) 0)
(vector-ref #(1 2 3) 0) (nth [1 2 3] 0) (elt [1 2 3] 0)
set vector element (setq v #(1 2 3))
(setf (aref v 2) 4)
(define v (vector 1 2 3))
(vector-set! v 2 4)
(replace { 2 4 } [1 2 3]) (setq v #(1 2 3))
(setf (aref v 2) 4)
vector to list
 
(coerce #(1 2 3) 'list) (vector->list #(1 2 3)) (seq [1 2 3]) (coerce [1 2 3] 'list)
list to vector
 
(coerce '(1 2 3) 'vector) (list->vector '(1 2 3)) (vec '(1 2 3)) (coerce '(1 2 3) 'vector)
sequence data types list vector list vector hash-table string input-port range all collections and strings list vector
sequence predicate (typep '(1 2 3) 'sequence)
(typep #(1 2 3) 'sequence)
(sequence? '(1 2 3)) (seq? '(1 2 3))
(seq? (seq [1 2 3]))
(typep '(1 2 3) 'sequence)
(typep #(1 2 3) 'sequence)
list functions usable on sequences length reduce remove-if-not sort for for/list for/hash for/and for/or for/fold vectors support all list functions; seq will convert any other collection to an object which supports list functions length reduce remove-if-not
make-array (make-array '(4 3 2)
  :initial-element 0)
 
(make-array '(3 2)
  :initial-contents
  '((1 2) (3 4) (5 6)))
none none none
array access (setq a
  (make-array '(3 2)
    :initial-contents
    '((1 2) (3 4) (5 6))))
 
(aref a 2 1)
none none none
set array element (setf (aref a 2 1) 7) none none none
array dimensions (setq a
  (make-array '(4 3 2)
    :initial-element 0))
 
(array-rank a)
(array-dimensions a)
(array-dimension a 0)
none none none
make-hash (setq h (make-hash-table)) (define h (make-hash))
(define ih (make-immutable-hash '(("hello" . 5))))
(def h (hash-map "hello" 5)) (setq h
  (make-hash-table
    :test 'equal))
hash literal
 
none #hash(("hello" . 5) ("goodbye" . 7)) {"hello" 5 "goodbye" 7} none
put-hash (setf (gethash "hello" h) 5) (hash-set! h "hello" 5)
(define ih2 (hash-set ih "goodbye" 7))
none
(def h2 (assoc h "goodbye" 7))
(puthash "hello" 5 h)
get-hash
 
(gethash "hello" h) (hash-ref h "hello") (get h "hello") (gethash "hello" h)
hash key not found nil error nil nil
rem-hash (remhash "hello" h) (hash-remove! h "hello")
 
(define ih2
  (hash-remove ih "hello"))
none
(def h2 (dissoc h "hello"))
(remhash "hello" h)
hash size
 
(hash-table-count h) (hash-count h) (count h) (hash-table-count h)
iterate over hash entries (maphash
  (lambda (k v)
    (print k)
    (print v))
  h)
(hash-for-each h
  (lambda (k v)
    (printf "~a~n" k)
    (printf "~a~n" v)))
(doseq [p h]
  (println (first p))
  (println (second p)))
(maphash
  (lambda (k v)
    (print k)
    (print v))
  h)
map hash to list none (define hkeys (hash-map h (lambda (k v) k)))
(define hvals (hash-map h (lambda (k v) v)))
(def hkeys (map (fn [p] (first p)) h))
(def hvals (map (fn [p] (second p)) h))
none
defstruct (defstruct account id balance) (define-struct account (id (balance #:mutable))) (defstruct account :id :balance) (defstruct account id balance)
struct (setq a
  (make-account
    :id 3
    :balance 17.12))
(define a (make-account 3 17.12)) (def a (struct account 3 17.12)) (setq a (make-account :id 3 :balance 17.12))
struct getter
 
(account-id a) (account-id a) (:id a) (account-id a)
struct setter
 
(setf (account-balance a) 0) (set-account-balance! a 0) none (setf (account-balance a) 0)
struct predicate
 
(account-p a) (account? a) none (account-p a)
range none (in-range 1 101) use in for constructs (range 1 101) none
list comprehension none (for*/list ((file "ABCDEFGH") (rank (in-range 1 9))) (printf "~a~a" file rank)) (for [file "ABCDEFGH" rank (range 1 9)] (format "%c%d" file rank)) none
functions and scope
common lisp scheme clojure emacs lisp
let (let ((x 3) (y 4))
  (+ x y))
(let ((x 3) (y 4))
  (+ x y))
(let [x 3 y 4]
  (+ x y))
(let ((x 3) (y 4))
  (+ x y))
use lexical-let for lexical scope
let* (let* ((x 3) (y (* x x)))
  (+ x y))
(let* ((x 3) (y (* x x)))
  (+ x y))
(let [x 3 y (* x x)]
  (+ x y))
(let* ((x 3) (y (* x x)))
  (+ x y))
use lexical-let* for lexical scope
define function
 
(defun add (x y) (+ x y)) (define (add x y) (+ x y)) (defn add [x y] (+ x y)) (defun add (x y) (+ 1 2))
optional argument (defun add (a &optional b)
  (if (null b) a (+ a b)))
(define (add a (b null))
  (if (null? b) a (+ a b)))
(defn add ([a] a) ([a b] (+ a b)))
no syntax error if called with more than 2 args:
(defn add [a & [b]]
  (if (nil? b) a (+ a b)))
(defun add (a &optional b)
  (if (null b) a (+ a b)))
variable number of arguments (defun add (a &rest b)
  (if (null b)
    a
    (+ a (eval (cons '+ b)))))
(define (add a . b)
  (if (null? b)
    a
    (+ a (apply + b))))
(defn add [a & b]
  (if (nil? b) a (+ a (apply + b))))
(defun add (a &rest b)
  (if (null b)
    a
    (+ a (eval (cons '+ b)))))
default value (defun add (a &optional (b 0))
  (+ a b))
racket:
(define (add a (b 0)) (+ a b))
(defn add
  ([a] (add a 0))
  ([a b] (+ a b)))
none
named parameter (defun logarithm (&key number base)
  (/ (log number) (log base)))
 
(logarithm :base 2 :number 8)
none (defn logarithm [{x :number b :base}] (/ (Math/log x) (Math/log b)))
(logarithm {:base 2 :number 8})
(defun logarithm
  (&key number &key base)
  (if base
    (/ (log number) (log base))
    (log number)))
 
order significant, not key names:
(logarithm :foo 8 :bar 2)
return multiple values (defun sqrts (x)
  (values (sqrt x) (- (sqrt x))))
(define (sqrts x)
  (values (sqrt x) (- (sqrt x))))
(defn sqrts [x] (list (Math/sqrt x) (- (Math/sqrt x)))) values creates a list:
(defun sqrts (x)
  (values (sqrt x) (- (sqrt x))))
assign multiple values to local variables (multiple-value-bind (r1 r2)
  (sqrts 3)
  r2)
(let-values
  (((r1 r2) (sqrts 3)))
  r2)
(let [[r1 r2] (sqrts 3)] r2) (multiple-value-bind (r1 r2)
  (sqrts 3) r2)
assign multiple values to global variables (multiple-value-setq (r1 r2)
  (sqrts 3))
(define-values (r1 r2) (sqrts 3)) none (multiple-value-setq (r1 r2)
  (sqrts 3))
convert list to multiple values (values-list '(1 2 3)) (apply values '(1 2 3)) multiple values are lists multiple values are lists
assign multiple values to list (multiple-value-list (sqrts 3)) (call-with-values
  (lambda () (sqrts 3))
  list)
multiple values are lists multiple values are lists
tail call optimization yes for sbcl yes yes with recur no
get docstring
 
(describe #'mapcar) none (doc map) (describe-function 'mapcar)
define function with docstring (defun add (x y)
  "add x and y"
  (+ x y))
none (defn add "add x and y" [x y]
  (+ x y))
(defun add (x y)
  "add x and y"
  (+ x y))
apropos and documentation search none none (apropos #"^add$")
(find-doc #"add \S+ and \S+")
(apropos "^add$")
none
execution control
common lisp scheme clojure emacs lisp
progn
 
progn prog1 prog2 begin none none
r6rs:
begin begin0 none
do none none progn prog1 prog2
loop (setq i 1)
(loop (print "hello")
  (if (> i 10)
    (return)
    (setq i (+ i 1))))
none, use recursion (loop [i 1]
  (if (<= i 10)
      (do (println "hello")
          (recur (+ i 1)))))
(setq i 1)
(loop (print "hello")
      (if (> i 10)
          (return)
          (setq i (+ i 1))))
do (do ((i 1) (sum 0))
  ((> i 100) sum)
  (setq sum (+ sum i))
  (setq i (+ i 1)))
do* initializes serially
none none (do ((i 1) (sum 0))
    ((> i 100) sum)
    (setq sum (+ sum i))
    (setq i (+ i 1)))
do* initializes sequentially
dotimes (dotimes (i 10 nil)
  (format t "hello~%"))
none (dotimes [_ 10]
  (println "hello"))
(dotimes (i 10 nil)
  (print "hello\n"))
if
 
(if (< x 0) (- x) x) (if (< x 0) (- x) x) (if (< x 0) (- x) x) (if (< x 0) (- x) x)
when (when (< x y)
  (print "x is less ")
  (print "than y"))
racket:
(when (< x y)
  (display "x is less ")
  (display "than y"))
(when (< x y)
  (println "x is less ")
  (println "than y"))
(when (< x y)
  (print "x is less ")
  (print "than y"))
error
 
(error "failed") (error "failed") (throw (Exception. "failed")) (error "failed")
handle error (handler-case
  (error "failed")
  (simple-error (e)
    (format t "error: ~a" e)))
(with-handlers
  ((exn:fail?
     (lambda (e)
       (printf "error: ~a"
         (exn-message e)))))
  (error "failed"))
(try (throw (Exception. "failure"))
  (catch Exception e
    (printf "error: %s"
      (.getMessage e))))
(condition-case e
  (error "failed")
  (error (message "error: %s"
    (error-message-string e))))
define exception (define-condition odd-err (error)
  ((num :accessor odd-err-num
        :initarg :num))
  (:report
    (lambda (e s)
      (format s "odd number: ~a"
        (odd-err-num e)))))
(define exn:odd-err? "odd number") only symbols and keywords can be thrown and caught
throw exception (error 'odd-err :num 7) (raise exn:odd-err?) (throw (Exception. "failed")) (throw 'odd-err t)
catch exception (handler-case (/ 1 0)
  (division-by-zero ()
    (progn
      (format t "division by zero")
      nil)))
(with-handlers ((exn:fail? (lambda (e) (begin (printf "division by zero~n") null)))) (/ 1 0)) (try (/ 1 0) (catch ArithmeticException _ (do (println "division by zero") nil))) (catch 'failed (throw 'failed nil) t)
restart-case (defun halve (l)
  (mapcar (lambda (x)
    (restart-case
      (if (= (rem x 2) 0) (/ x 2)
        (error 'odd-error :num x))
      (round-down () (/ (- x 1) 2))
      (round-up () (/ (+ x 1) 2)))) l))
none none
invoke-restart (handler-bind
  ((odd-err
      (lambda (c)
        (invoke-restart
          'round-down))))
      (halve '(1 2 4 9)))
none none
finally clause (unwind-protect
  (error "failure")
  (print "clean up"))
none (try (throw (Exception. "failure"))
     (finally (println "clean up")))
(unwind-protect
  (error "failure")
  (print "clean up"))
lazy evaluation (define x (delay (/ 1 0)))
(promise? x)
(+ 1 (force x))
continuations (define cc null)
(+ 1 (call/cc (lambda (x) (set! cc x) 0)))
(cc 5)
create thread (.start (Thread. #(println "running…")))
wait on a thread (def t (Thread. #(Thread/sleep (* 30 1000))))
(.start t)
(.join t)
environment and i/o
common lisp scheme clojure emacs lisp
format string to stdout (format t "~s ~d: ~2$~%"
  "foo"
  7
  13.7)
(printf "~a ~a: ~a~n"
  "foo"
  7
  (/ (round (* 13.7 100)) 100))
(printf "%s %d %.2f\n" "foo" 7 13.7) (princ
  (format "%s %d %6.2f\n"
    "foo"
    7
    13.7))
print string to stdout with newline (defun println (s)
  (format t "~a~%" s))
 
(println "hello")
(define (println s)
  (printf "~a~n" s))

(println "hello")
(println "hello")
external command (run-program "ls" '( "/etc")) (require scheme/system)
(system "ls /etc")
(.exec (Runtime/getRuntime) "ls") (shell-command "ls /etc")
command line arguments *posix-argv* current-command-line-arguments *command-line-args* in shebang mode only:
command-line-args or argv
environment variables (posix-getenv "HOME") (getenv "HOME") (System/getenv "HOME") (getenv "HOME")
open file (setq in (open "/etc/passwd")) (define in (open-input-file "/etc/passwd")) (def in (java.io.BufferedReader. (java.io.FileReader. "/etc/passwd"))) to read file into buffer:
find-file "/etc/passwd")
read line
 
(setq line (read-line in)) (define line (read-line in)) (def line (.readLine in)) none
close file
 
(close in) (close-input-port in) (.close in) (kill-buffer "passwd")
libraries and modules
common lisp scheme clojure emacs lisp
loading a file
 
(load "a.lisp") (load "a.rkt") (load-file "a.clj") (load-file "a.el")
loading a library
 
(require a) (require 'a) (load "a")
objects
common lisp scheme clojure emacs lisp
define class (defclass rectangle ()
  (
    (height
      :accessor rectangle-height
      :initarg :height)
    (width
      :accessor rectangle-width
      :initarg :width)))
(define rectangle%
  (class object%
    (init width)
    (init height)
    (super-new)
    (define curr-height height)
    (define curr-width width)
    (define/public (get-height)
      curr-height)
    (define/public (get-width)
      curr-width)
    (define/public (set-height ht)
      (set! curr-height ht))
    (define/public (set-width wd)
      (set! curr-width wd))))
use java:
public class Rectangle {
  public float height;
  public float width;
  public Rectangle(float h, float w) {
    this.height = h;
    this.width = w;
  }
  public void setHeight(float h) {
    this.height = h;
  }
  public void setWidth(float w) {
    this.width = w;
}
make instance (make-instance 'rectangle
  :height 3
  :width 7)
(define rect
  (new rectangle
    (height 7)
    (width 3)))
(import 'Rectangle)
(def r (Rectangle. 7 3))
read attribute
 
(rectangle-height rect) (send rect get-height) (.height r)
write attribute
 
(setf (rectangle-height rect) 4) (send rect set-height 4) (.setHeight r 8)
define method (defmethod area ((figure rectangle))
  (* (rectangle-height figure)
    (rectangle-width figure)))
(define/public (area)
  (* curr-height curr-width))
(defmulti area class)
(defmethod area Rectangle [r] (* (.height r) (.width r)))
invoke method
 
(area rect) (send rect area) (area r)
universal superclass standard-object t object% Object
multiple inheritance yes no only one direct superclass; can implement multiple interfaces
macros
common lisp scheme clojure emacs lisp
backquote and comma (setq op '+)
(eval `(,op 1 1))
(define op '+)
(eval `(,op 1 1))
(eval (quasiquote ((unquote op) 1 1)))
(def op +)
(eval `(,op 1 1))
(setq op '+)
(eval `(,op 1 1))
defmacro (defmacro rpn (arg1 arg2 op)
  (list op arg1 arg2))
(define-syntax-rule (rpn arg1 arg2 op) (op arg1 arg2)) (defmacro rpn [arg1 arg2 op]
  (list op arg1 arg2))
(defmacro rpn (arg1 arg2 op)
  (list op arg1 arg2))
defmacro w/ backquote (defmacro rpn (arg1 arg2 op)
  `(,op ,arg1 ,arg2))
(define-syntax-rule (rpn3 arg1 arg2 op)
  (eval ‘(,op ,arg1 ,arg2)))
(defmacro rpn [arg1 arg2 op] `(~op ~arg1 ~arg2)) (defmacro rpn (arg1 arg2 op)
  `(,op ,arg1 ,arg2))
macro predicate (macro-function rpn) none none none
macroexpand (macroexpand ’(rpn 1 2 +)) (syntax-object->datum (expand-to-top-form '(rpn 1 2 +))) (macroexpand '(rpn 1 2 +)) (macroexpand '(rpn 1 2 +))
splice quote (defmacro add ( &rest args )
  `(+ ,@args))
(define-syntax-rule ( add first …) (+ first …)) (defmacro add [ & args ] `(+ ~@args)) (defmacro add ( &rest args )
  `(+ ,@args))
recursive macro (defmacro add (a &rest b)
  `(if (null ',b)
    (+ ,a)
    (+ ,a (add ,@b))))
(define-syntax add (syntax-rules ()
  [(add x) x]
  [(add x y) (+ x y)]
  [(add x y …) (+ x (add y …))]))
(defmacro add ([a] `(+ ~a)) ([a & b] `(+ ~a (add ~@b)))) (defmacro add (a &rest b)
  `(if (null ',b)
    (+ ,a)
    (+ ,a (add ,@b))))
hygienic
 
no yes with # suffix no
local values (defmacro square-sum (x y)
  (let ((sum (gensym)))
    `(let ((,sum (+ ,x ,y)))
      (* ,sum ,sum))))
(define-syntax-rule (square-sum x y)
  (let ((sum (+ x y)))
    (* sum sum)))
(defmacro two-list [x] `(let [arg# ~x] (list arg# arg#))) (defmacro square-sum (x y)
  (let ((sum (gensym)))
    `(let ((,sum (+ ,x ,y)))
      (* ,sum ,sum))))
java interoperation
common lisp scheme clojure emacs lisp
version used on jvm ABCL 0.24.0 Kawa 1.11 Clojure 1.2.1 none
extra libraries used (require 'srfi-1)
new (setq rnd
  (jnew
    (jconstructor
      "java.util.Random")))
(define rnd (java.util.Random:new)) (def rnd (new java.util.Random))
(def rnd (java.util.Random.))
method (jcall (jmethod "java.util.Random" "nextFloat") rnd)
(jcall (jmethod "java.util.Random" "nextInt" "int") rnd 100)
(java.util.Random:nextFloat rnd)
(*:nextFloat rnd)
(java.util.Random:nextInt rnd)
(*:nextInt rnd)
(. rnd nextFloat)
(.nextFloat rnd)
(. rnd nextInt 10)
(.nextInt rnd 10)
class method
 
(java.lang.Math:sqrt 2) (Math/sqrt 2)
chain
 
import (import '(java.util Random))
(def rnd (Random.))
to java array (to-array '(1 2 3))
(into-array Integer '(1 2 3))
__________________________________________ __________________________________________ __________________________________________ __________________________________________

General Footnotes

version used

Versions used to verify data in the cheat sheet.

version

How to determine the version.

repl

How to invoke the repl from the command line.

scheme:

Racket also provides a GUI repl environment called DrRacket.

clojure:

The clojure repl saves the result of each evaluation in the variables *1, *2, … and the last exception in *e.

running in emacs

How to run in emacs.

common lisp:

SLIME

Running sbcl from within emacs with SLIME provides syntax highlighting, parantheses matching, and the ability to edit and resubmit commands.

(add-to-list 'load-path "~/.emacs.d/slime/")         ; location of slime elisp 
(setq inferior-lisp-program "/opt/local/bin/sbcl")
(require 'slime)
(slime-setup)

clojure:

clojure-mode can be installed via ELPA in emacs, and enables running clojure with SLIME and syntax highlighting. I haven't been able to get it to work, so I have been running clojure from a shell within emacs, which highlights matching parens and gives some readline ability.

shebang

How to have a script run by the interpreter automatically. Replace the given path with the path to the interpreter on your system.

emacs lisp

To run some lisp code from within emacs, use M-x load or M-x load-file. The first command will use the list of strings in load-path to search for the file. It is not necessary to specify the .el or .elc suffix if the file has one.

The following snippet is an emacs lisp shebang script implementation of cat:

#!/usr/local/bin/emacs --script
(condition-case nil
  (let (line)
    (while (setq line (read-from-minibuffer ""))
        (princ line)
        (princ "\n")))
  (error nil))

An implementation of echo:

#!/usr/local/bin/emacs --script
(condition-case nil
  (progn
    (dotimes (i (length argv) nil)
            (princ (nth i argv))
            (princ " "))
    (princ "\n"))
  (error nil))

compiling

scheme

Compiling a.ss creates the byte-code compiled file a_ss.zo, which will be used by mzscheme in preference to the source code if it encounters

(require a)

making a standalone executable

common lisp

A standalone executable is created by the sb-ext:save-lisp-and-die function.

scheme

In order for code to be compiled as a standalone executable, it must be packaged as a module. This can be accomplished by putting the #lang scheme shorthand the top of the file. All functions that are defined in the module will be executed in order. Here is a simple example:

#lang scheme
(define hello
  (printf "Hello world!~n"))

A standalone executable can be created with DrScheme using Scheme | Create Executable…

emacs

Building Emacs

cell types

The different cell types. A lisp-1 only stores a single entity under a symbol in a given environment. A lisp-2 stores multiple entities, and which entity a symbol will resolve to depends on how the symbol is used. In particular, a value and a function can be stored under the same symbol without collision.

case sensitive

Whether symbols are case sensitive. Common lisp is case insensitive, and as a result eq and EQ invoke the same function.

argument separator

What is used to separate the operator and data of a S-expression.

type-of

How to get the data type of the entity referred to by a symbol.

type predicates

Some basic data type predicates.

set property

How to associate additional data with a symbol. In the example, the symbol is foo, the property is :prop, and the value is 13.

**clojure:##

The properties associated with a symbol must be set when the value for the symbol is set.

get property

How to get the value of a property.

remove property

How to remove a property from a symbol.

quoted symbol

How to prevent the evaluation of a symbol.

special reader characters

In lisps other than clojure, any character can be used in a symbol. Some characters are special to the reader and must be escaped to include them in a symbol. The reader will interpret a sequence of characters starting with a digit as a number instead of a symbol, so escaping must be used to create such a symbol.

common lisp:

Common Lisp is case insensitive, and the reader converts all letters to upper case. A symbol consisting of just periods "." must be escaped. Symbols that start and end with an asterisk "*" may conflict with system defined special variables.

scheme:

# is only disallowed by the reader at the beginning of symbols. A symbol consisting of a single period must be escaped.

escaping special reader characters

How to escape characters which are special to the reader.

clojure:

Clojure does not have a mechanism for escaping special reader characters. As a result some characters cannot be used in a symbol.

keyword

Keywords are pre-defined symbols that evaluate to their printed representation. The reader recognizes them by the initial colon, or in the case of Scheme, by the initial "#:". In Scheme it is an error to use a keyword as an expression.

comment

#| |# delimited comments in Common Lisp and Scheme can span multiple lines, and thus can be used to comment out code.

clojure:

Code with balanced parens can be commented out in the following manner:

(comment
(+ 1 1)
)

Ten Primitives Footnotes

McCarthy introduced the ten primitives of lisp in 1960. All other pure lisp functions (i.e. all functions which don't do I/O or interact with the environment) can be implemented with these primitives. Thus, when implementing or porting lisp, these are the only functions which need to be implemented in a lower language. The way the non-primitives of lisp can be constructed from primitives is analogous to the way theorems can be proven from axioms in mathematics.

The primitives are: atom, quote, eq, car, cdr, cons, cond, lambda, label, apply.

One method of implementing logic and arithmetic with the ten primitives is Church encoding which represents natural numbers and logical values with lambda functions. Church numerals are not an efficient way to represent natural numbers; practical implementations implement arithmetic using underlying machine instructions.

atom

atom is is a predicate which returns false for cons cells, and true for anything else. All lists except for the empty list are cons cells.

scheme

Scheme lacks atom, but cons? is its logical negation.

clojure

Clojure lacks cons cells. Thus atom if implemented in the language would always return true. However, (not (list? x)) is closer to the spirit and certainly more useful. Because nil is not the empty list in clojure there is also ambiguity about what the value of (atom ()) would be.

quote

All lisps have a single quote macro abbreviation for quote. Here are identical ways to quote a symbol and a list:

(quote a)
'a

(quote (+ 3 7))
'(+ 3 7)

eval is a one-sided inverse of quote. If X is arbitrary lisp code, then the following are identical

X
(eval (quote X))

eq, equal, =

In his 1960 paper, McCarthy described eq as undefined if either or both arguments are not atomic. Common Lisp and Scheme (eq?) return true if the arguments both evaluate to the same list in memory, otherwise false. equal and equal? (Scheme) return true if the arguments evaluate to lists with the same elements as determined by calling equal or equal? recursively.

In Common Lisp and Scheme, = can only be called on numeric arguments. The predicates for whether a symbol is numeric are numberp and number?, respectively.

Clojure dispenses with eq and equal and defines = to be equivalent to the Common Lisp equal.

car

Because car and cdr are abbreviations for parts of the word of the IBM 704, there is a trend to replace them with first and rest. However, car and cdr are short, and convenient notation exists for abbreviating nested calls to car and cdr.

In terms of car, cdr, and combinations thereof, here is what the dialects define:

common lisp r5rs racket clojure emacs lisp
car,first car car,first first car,first
cadr,second cadr cadr,second second,fnext cadr,second
caddr,third caddr caddr,third caddr,third
cadddr,fourth cadddr cadddr,fourth cadddr,fourth
fifth fifth fifth
sixth sixth sixth
seventh seventh seventh
eighth eighth eight
ninth ninth night
tenth tenth tenth
cdr, rest cdr cdr, rest rest,next cdr, rest
cddr cddr cddr cddr
cdddr cdddr cdddr cdddr
cddddr cddddr cddddr cddddr
caar caar caar ffirst caar
cdar cdar cdar nfirst cdar

cdr

common lisp

cdr and rest return nil when called on an empty list.

scheme

cdr and rest raise an error when called on an empty list.

clojure

rest returns an empty set () when called on an empty or singleton list, whereas next returns nil. In clojure, the empty set evaluates as true in a boolean context and nil evaluates as false.

cons

clojure

Clojure does not implement a list as a linked list of cons cells. The second argument to cons must be a list.

cond

lambda

clojure:

(#(+ %1 %2) 1 2)

label

apply

Arithmetic and Logic Footnotes

falsehoods

Values which evaluate to false in a boolean context.

common lisp

nil and the empty list () are identical.

scheme

The empty list does not evaluate as false in a boolean context. There is no predefined symbol nil.

clojure

nil evaluates as false in a boolean context, but is not identical as the empty list.

emacs lisp

nil and empty list () are identical.

true, is true symbol?

The symbol for true

nil, is () null?, is () symbol?

(eq nil ())

is true in common lisp and emacs lisp.

(eq? () null)

is true in Scheme.

logical operators

The logical operators.

numeric predicates

A selection of numeric predicates.

realp and real? are true of all numbers which have a zero imaginary component. floatp and inexact? are true if the number is being stored in a floating point representation.

scheme:

The following all evaluate as #t:

(rational? 1.1)
(rational? (sqrt 2))
(rational? pi)

largest positive integer

Common lisp, Scheme, and Clojure have arbitrary length integers.

closure of integers under division

The number system that containing the potential results of integer division. In mathematics, the closure of integers under division is the rationals, and this is true for common lisp, scheme, and clojure as well.

Emacs lisp performs integer division (i.e. computes the quotient), so the closure of the integers under division is the integers.

operators

In Lisp, + and * take zero or more arguments and - and / take one or more arguments. With zero arguments + and * return the additive and multiplicative identities 0 and 1. With one argument + and * return the argument and - and / return the additive and multiplicative inverses: i.e. the negation and the reciprocal. When evaluating 3 or more arguments - and / are computed from left to right: i.e. (- 3 4 5) is computed as (- (- 3 4) 5).

clojure:

Math.pow returns a double.

emacs:

Unary division (i.e. computing the reciprocal) generates a wrong number of arguments error.

relational operators

other functions

arithmetic truncation

For rounding, floor, and ceiling, the return value is integer if the argument is rational and floating point if the argument is floating point, unless otherwise noted.

scheme:

inexact->exact can be used to convert a float returned by round, ceiling, or floor to an integer.

clojure:

Math/round always returns an integer and throws and error if called on a rational. Math/floor and Math/ceil can be called on a rational, but always return a float.

emacs:

round, ceiling, and floor return integers. fround, fceiling, and ffloor return floats.

convert from string, to string

How to convert strings to numbers, and numbers to strings.

common lisp:

read-from-string invokes the reader, so the return value is not guaranteed to be a floating point number.

Here is a parse-float function which will convert all real numeric types to floats and raise a simple error if another condition is encountered.

(defun parse-float (s)
  (let ((readval (handler-case
                  (read-from-string s)
                  (sb-int:simple-reader-error nil)
                  (end-of-file nil))))
    (cond ((realp readval ) (+ readval 0.0))
          (t (error (concatenate 'string "not a float: " s))))))

bitwise operators

scheme:

The bitwise operators implemented by Gambit and Racket are specified in the withdrawn standard SRFI 33.

emacs:

Also has ash, which gives a different value when both arguments are negative.

quotient and remainder

(sqrt -2)

The value of (sqrt -2). Common lisp and Scheme support complex numbers. Clojure and Emacs Lisp do not.

decomposition of integer, rational, complex

For absolute value, the type of the return value is the same of the type of the argument.

scheme:

The scheme/math library must be loaded to use sgn.

clojure:

Math/signum only operates on a float and returns a float

random integer, uniform float, normal float

How to generate a random integer, and a random float in a uniform and a normal distribution.

String Footnotes

character literals

The syntax for character literals. The first literal uses the letter "a" as an example of how to write a literal for all ASCII printing characters.

common lisp:

Characters are of type standard-char. The predicate is characterp.

scheme:

The predicate is char?.

clojure:

Characters are of type java.lang.Character.

emacs:

Characters are of type integer and can be manipulated by arithmetic operators. characterp and integerp are synonyms.

string literal

The syntax for a string literal.

string escapes

A list of escape sequences that can be used in string literals.

emacs lisp:

The \x escape sequence is followed by one to six hex digits. Because a variable number of hex digits can be used, it may be necessary to indicate the end of the sequence with a backslash and a space, e.g. the following string literal is "λ123":

  "\x3bb\ 123"

character access

How to get the character at a given position in a string.

find substring

Find the location of a substring in a string.

extract substring

length

constructors

comparison

common lisp:

Here is the complete list of string comparison functions:

string=
string<
string>
string<=
string>=
string/=

There are also case insensitive versions of the above functions:

string-equal
string-lessp
string-greaterp
string-not-greaterp
string-not-lessp
string-not-equal

scheme:

Case sensitive string comparison:

string<=?
string<?
string=?
string>=?
string>?

Case insensitive string comparison:

string-ci<=?
string-ci<?
string-ci=?
string-ci>=?
string-ci>?

emacs lisp:

Emacs has only these string comparison functions, all of which are case sensitive:

string=
string-equal
string<
string-lessp

string= and string-equal are synonyms, as are string< and string-lessp.

case

trim

emacs:

An implementation of trim:

(defun trim (s)
  (let ((s1 (replace-regexp-in-string "[ \t]*$" "" s)))
    (replace-regexp-in-string "^[ \t]*" "" s1)))

concat

split

join

format

regular expressions

common lisp

http://weitz.de/cl-ppcre/

emacs lisp

string-match returns the first index of the first matching substring, or nil.

The following code moves the point to next position following the point that matches the argument, and returns the index of the that position.

(re-search-forward "hello")

regex substitution

regex special characters

List Footnotes

list literal

pair literal

(car '())

(cdr '())

(eval '())

A practical advantage of having (eval '()) be equal to '() is that the empty list doesn't have to be quoted.

list functions

nth

nth and list-ref count from zero. nth returns nil if the index is too large. list-ref throws an error.

index of list element

How to get the index of a list element. The first element of a list has an index of zero.

last butlast

In clojure, last and butlast are analogs of first and rest which operate at the end of a list. If X is a list, then the following code pairs are identities:

(last X)
(first (reverse X))

(butlast X)
(reverse (rest (reverse X)))

The analogy breaks down in Common Lisp because last returns a list with a single element.

set-car set-cdr

common lisp:

The following code pairs perform the same operation on the list:

(setf (car l) 3)
(rplaca l 3)

(setf (cdr l) '(4 5 6))
(rplacd l '(4 5 6))

However, they are not identical because rplaca and rplacd return the modified list instead of their 2nd argument.

scheme:

Racket provides a separate interpreter plt-r5rs for an R5RS compliant version of Scheme. Also, the language can be set to R5RS within DrRacket.

emacs lisp:

Also has setf.

sort

assoc

clojure

In Clojure, assoc returns a new association with the specified values replaced:

(def numbers {1 :one 2 :two 3 :three 4 :four})
(def jumble (assoc numbers 1 :uno 3 :drei 4 :quatre))

getf

scheme:

How to implement getf in Scheme:

(define (getf lst key (default null))
    (cond ((null? lst) default)
          ((null? (cdr lst)) default)
          ((eq? (car lst) key) (cadr lst))
          (else (getf (cddr lst) key default))))

map

common lisp

The lambda can accept multiple arguments:

(mapcar '+ '(1 2 3) '(4 5 6))

scheme

(map + '(1 2 3) '(4 5 6))

clojure

(map + '(1 2 3) '(4 5 6))

emacs lisp

mapcar does not accept multiple argument lambdas

filter

common lisp

Also the negative version:

(remove-if (lambda (x) (> x 2)) '(1 2 3))

clojure

Also the negative version:

(remove #(> % 2) '(1 2 3))

emacs lisp

Also has negative version:

(remove-if (λ (x) (> x 2)) '(1 2 3))

reduce (left fold)

right fold

clojure:

How to define foldr:

(defn foldr [f init list] (reduce #(f %2 %1) (reverse list)))

dolist

take

Here is how to define take for common lisp or emacs lisp:

(defun take (n l)
  (cond ((< n 0) (error "index negative"))
        ((= n 0) ())
        ((null l) (error "index too large"))
        (t (cons (car l) (take (- n 1) (cdr l))))))

drop

push and pop

scheme:

Here is an implementation of push and pop in Racket using boxes:

(define (push x a-list)
  (set-box! a-list (cons x (unbox a-list))))

(define (pop a-list)
  (let ((result (first (unbox a-list))))
    (set-box! a-list (rest (unbox a-list)))
    result))

clojure:

Note the in clojure, pop only returns the first element; the original list is left unmodified.

Other Container Footnotes

vector literal

scheme

#(1 2 3) creates an immutable vect. (vector 1 2 3) creates a mutable vector.

vector access

set vector element

scheme

vector-set! throws an error if called on an immutable vector.

vector to list

list to vector

abstract sequence

Lists and vectors support the same operations; the only difference is the speed at which the operations can be performed. It is a convenience for the developer if functions that perform the operations have the same name; i.e. if lists and vectors are members of an abstract sequence type. Clojure has gone furthest in this direction, making all the customary list functions work on vectors as well. In common lisp and emacs lisp, some of the list functions also work on vectors, and some don't. In Scheme none of the list functions work on vectors.

sequence data types

The containers that respond to sequence functions.

sequence predicate

list functions usable on sequences

make-array

In Lisp terminology, both arrays and vectors refer to collections which are of fixed size; vectors are arrays with rank 1. Only common lisp supports arrays with rank greater than 1.

array access

set array element

array dimensions

array-rank returns the number of indices required to specify an element in the array. array-dimensions returns the size of the array; the number of cells is the product of the elements of the list.

make hash

scheme

Use the following to get access to the hash functions:

(require scheme/dict)

put hash

Put a key/value pair in a hash.

clojure

The hash map is immutable. The assoc function returns a new version of the hash with the additional key/value pairs provided as arguments.

get-hash

Lookup a value in a hash by key.

hash key not found

scheme:

Racket throws and error when the key is not found. Here is how to handle the error and return a null when the key is not found:

(with-handlers ((exn:fail? (lambda (e) null))) (get h "goodbye"))

rem-hash

hash size

map hash

defstruct

struct

struct getter

struct setter

struct predicate

range

list comprehension

Functions and Scope Footnotes

let, let*

Traditionally let performs its assignments in parallel and let* serially.

clojure

In Clojure, let and let* are synonyms and both perform serial assignment.

emacs

Note that let uses dynamic scope. Use lexical-let for lexical scope:

ELISP> (let ((x 3)) (defun get-x () x))
get-x
ELISP> (get-x)
*** Eval error ***  Symbol's value as variable is void: x
ELISP> (let ((x 4)) (get-x))
4
ELISP> (lexical-let ((x 3)) (defun get-x-2 () x))
get-x-2
ELISP> (get-x-2)
3
ELISP> (lexical-let ((x 4)) (get-x-2))
3

define function

optional argument

variable number of arguments

default value

named parameter

common lisp:

In common lisp, named parameters are optional. Named values can be assigned default values:

 (defun logarithm (&key number (base 10)) (/ (log number) (log base)))

If a named parameter is not provided at invocation and has not been assigned a default value, then it is set to nil.

scheme:

How to Implement Named Parameters in Scheme

emacs lisp:

In emacs lisp named parameters are mandatory. A runtime error results in they are not provided when the function is invoked.

tail call optimization

common lisp:

The ANSI Common Lisp specification does not require an implementation to perform tail call optimization.

get docstring

How to get the documentation string for a function.

common lisp:

describe returns the documentation string with additional information such as the function signature. To get just the documentation string use this:

(documentation #'mapcar 'function)

define function with docstring

How to define a function that has a documentation string.

apropos and documentation search

How to search definitions and documentation.

Apropos takes a pattern and returns all defined symbol names which match the pattern.

clojure:

apropos returns matching symbol names as a list.

find-doc searches all documentation strings and writes any which match to standard out.

Both apropos and find-doc can take a string or a regular expression as an argument.

emacs lisp:

apropos displays the documentation for matching definitions in the *Apropos* buffer. The argument is a string but will be treated as a regular expression.

Execution Control Footnotes

progn

progn and its equivalents in other dialects returns the value of the last expression. Common Lisp and Emacs Lisp also have prog1 and prog2 for returning the value of the 1st or 2nd expression.

loop

do

dotimes

if

when

error

handle error

scheme:

Calling error raises an exception of type exn:fail

emacs:

In the example:

(condition-case nil (error "failed") (error (message "caught error") nil))

the 2nd argument to condition-case is the code which might raise an error, and the 3rd argument is the error handler. The error handler starts with condition to be caught. The last nil is the return value of the entire condition-case expression.

An error cannot be handled by catch. An uncaught throw will generate an error, which can be handled by a condition-case error handler.

define exception

How to define a custom exception with a payload.

common lisp:

The :report clause is not necessary. If defined it will be displayed if the exception is handled by the lisp debugger.

throw exception

emacs:

The 1st argument of an emacs throw expression identifies the type of exception, and the 2nd argument will be the return value of the catch expression that catches the exception.

catch exception

emacs

The following catch expression will return nil:

(catch 'failed (throw 'failed nil) t)

restart case

invoke restart

finally clause

scheme:

clojure:

Here is an optional technique for making sure that a file handle is closed:

(with-open [#^PrintWriter w (writer f)] (.print w content))

lazy evaluation

continuations

create thread

wait on thread

Environment and I/O Footnotes

formatted string to stdout

scheme

printf prints to stdout. format returns a string.

emacs lisp

The format statement returns the generated string. When used for i/o, it prints in the emacs minibuffer.

external command

command line arguments

emacs

The global variables command-line-args and argv are set when emacs is run in shebang mode: i.e. with the —script option. command-line-args contains the pathname used to invoke emacs, as well as any options processed by emacs at startup, in addition to any additional arguments. argv only contains the additional arguments.

environment variables

open file

read line

close file

Library and Module Footnotes

loading a file

How to load a file and evaluate the top level expressions.

common lisp

Does not display the result of any evaluations.

scheme

Displays the result of the last evaluation.

loading a library

Object Footnotes

define class

make instance

read attribute

write attribute

define method

invoke method

define subclass

universal superclass

multiple inheritance

Macro Footnotes

backquote and comma

defmacro

defmacro-backquote

macro predicate

macroexpand

macroexpand recursively expands a sexp until the head is no longer a macro. It does not expand arguments that are macros.

common lisp

Common lisp also has macroexpand-1, which will non-recursively expand a macro once. The head of the expansion may thus be a macro.

clojure

Clojure also has macroexpand-1. See above for an example of use.

emacs lisp

Emacs has macroexpand-all, which will recursively expand a sexp until head and arguments are free of macros.

splice quote

recursive macro

hygienic

Does the language have macros whose expansions are guaranteed not to introduce name collisions.

local values

Java Interoperation Footnotes

version used on jvm

extra libraries used

scheme:

The srfi-1 library brings in a common list functions which Kawa does not make available by default. See SRFI.

new

method

class method

chain

import

to java array

Common Lisp

ANSI Specification
Common Lisp: The Language 2nd Ed. gizpped download
SBCL User Manual
CLISP Man Page
CLiki: Common Lisp Wiki
Practical Common Lisp Seibel
ASDF Manual
Indenting Common Lisp
Riastradh's Lisp Style Rules Campbell
Quicklisp

Common Lisp was designed by committee. The initial standard was agreed upon in 1983, and the Common Lisp Object System (CLOS) was added in 1988. Common Lisp became an ANSI standard in 1994.

For the reference sheet we are using three implementations: SBCL, CLISP, and ABCL. SBCL (Steel Bank Common Lisp) is fast and feature complete. The only potential downside to SBCL is that the Windows port is considered experimental. CLISP, by contrast, is easy to install and works well on Windows. ABCL (Armed Bear Common Lisp) is a JVM implementation. There are other implementations that might be worth considering.

For a package manager we use Quicklisp. It works with SBCL, CLISP, and ABCL. Here is how to install it and use it to load the cl-ppcre library:

$ curl -O http://beta.quicklisp.org/quicklisp.lisp
$ sbcl
* (load "quicklisp.lisp")
* (quicklisp-quickstart:install)
* (ql:quickload "cl-ppcre")
* (cl-ppcre:all-matches "foo" "foo bar")

Quicklisp creates a quicklisp directory in the user's home directory. Once quicklisp is downloaded and installed, it can be used like this:

$ sbcl
* (load "~/quicklisp/setup.lisp")
* (ql:quickload "cl-ppcre")
* (cl-ppcre:all-matches "foo" "foo bar")

When using SBCL we can ensure that Quicklisp is automatically loaded at startup by putting the load command into the .sbclrc file:

$ cat ~/.sbclrc
(load "~/quicklisp/setup.lisp")

The equivalent file for CLISP is .clisprc.lisp:

$ cat .clisprc.lisp 
(load "~/quicklisp/setup.lisp")

For ABCL the file is .abclrc:

$ cat .abclrc
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))

Scheme

R5RS
R6RS
Guide: Racket
Reference: Racket
Gambit Documentation
Kawa Language Framework
Scheme Requests for Implementation (SRFI)
Scheme Links
Scheme Now
Chicken Scheme
Chicken Egg Index
MIT Scheme Reference

Scheme as a dialect of Lisp is characterized by lexical scope, mandatory tail call optimization, and first class continuations.

The R5RS standard (1998) added hygienic macros to the language. In all standards up to and including R5RS the standards body focused on defining a small core of features. The result was a language ideal for instruction or academic experimentation. The R6RS standard (2007) by contrast defined support for libraries, modules, networking, and Unicode. Most Scheme implementations only aim to be R5RS compliant. Racket is the only implementation which has implemented a significant portion of the R6RS features.

Because of the inconsistent adoption of R6RS, a universal package manager for all Scheme implementations is a difficult undertaking. Scheme Now (Snow) is an effort in this direction, but the package manager snowman doesn't work with Racket, Gambit, or Kawa, the implementations used in this reference sheet.

A process was initiated in 1998 called Scheme Request For Implementation (SRFI) which develops specifications for Scheme standard libraries. As of 2010 74 of the specifications have achieved a final status. Here is a page showing which SRFIs have been implemented for which Scheme implementations.

Racket ships with a large number of libraries in the collects directory of the installation which can be loaded with the require command, which takes a raw symbol which is the relative pathname from the collects directory to the file, not including the .rkt suffix. The Racket 5.1 distribution includes 50 SRFI libraries.

Racket also has a built in package management system. Browse the list of available packages. To install a package, click through to the detail page for the package and get the require string to load it. If the require string is executed by Racket, the library will be downloaded somewhere in the user's home directory. When I ran this on my Mac

$ racket
> (require (planet "spgsql.rkt" ("schematics" "spgsql.plt" 2 3)))

the files for the PostgreSQL database bindings were installed in ~/Library/Racket.

Chicken Scheme packages are called eggs. Use the command line utility chicken-install to install an egg. The egg can be loaded in the interpreter with the use commnad:

$ sudo chicken-install srfi-19
$ csi
#;1> (use srfi-19)
#;2> (define d (make-date 0 0 0 0 9 7 2011))
#;3> (leap-year? d)
#f

Clojure

Clojure Reference
Java 1.6 API

Calling Java

Here are the basics of calling Java code:

(def rnd (new java.util.Random))  ; create Java object
(. rnd nextFloat)  ; invoke method on object
(. rnd nextInt 10)  ; invoke method with argument
(. Math PI)  ; static member
(import '(java.util Random))  ; import

Clojure automatically imports everything in java.lang.

There are shortcuts for the above syntax:

(Random.)
(new Random)

Math/PI
(. Math PI)

(.nextInt rnd)
(. rnd nextInt)

Because they are primitive types and not objects, Clojure provides functions specific to Java arrays:

(make-array CLASS LEN)
(make-array CLASS DIM & DIMS)
(aset ARY IDX VAL)
(aset ARY IDX_DIM1 IDX_DIM2 ... VAL)
(aget ARY IDX)
(aget ARY IDX_DIM1 IDX_DIM2 ...)
(alength JARY)
(to-array SEQ)
(into-array TYPE SEQ)
(amap ARY I COPY EXPR)
(areduce ARY IDX  COPY INIT EXPR )

Emacs Lisp

GNU Emacs Manual
GNU Emacs Lisp Reference Manual
Emacs Starter Kit

To get an introduction to Emacs Lisp Programming from within Emacs use

  C-h i m Emacs Lisp Intro

Run M-x lisp-interaction-mode to put Emacs in lisp interaction mode. In lisp interaction mode the command C-x e will evaluate the s-expression on the current line. M-x eval-buffer will evaluate the entire buffer.

Use lisp interaction mode to define functions which can be called from Emacs. The following defines a function called dired-emacs-lisp for browsing the Emacs Lisp directory:

(defun dired-emacs-lisp ()
  "Open the Emacs Lisp directory in dired."
  (interactive)
   (dired "/Applications/Emacs.app/Contents/Resources/lisp"))

The directory is hard-coded into the function and may be different on your system. Once defined the function can be invoked with M-x dired-emacs-lisp. Not all Lisp functions can be called from Emacs. Those that can are called commands. The body of a command has an optional documentation string, followed by a call to interactive, followed by the code which executes when the command is invoked. The documentation string can be accessed from Emacs by running M-x describe-function and entering the name of the function when prompted.

The call to interactive is what makes a Lisp function a command. It can takes optional arguments. Use M-x describe-function on interactive to see a description of these arguments.

To bind the command to the key C-c l run the following in Lisp interaction mode:

(global-set-key "\C-cl" 'dired-emacs-lisp)

If it is desired to have the above command and key binding always available when Emacs starts up, put them in ~/.emacs.d/init.el.

Lisp History

Some of the Lisp dialects and implementations that predate Common Lisp are described here. The Software Preservation Group keeps a more complete list.

The Invention of Lisp: 1956-1962

Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I McCarthy 1960
Lisp 1.5 Programmer's Manual (pdf) 1962
History of Lisp McCarthy 1979
The Roots of Lisp (ps) Graham 2002

McCarthy was introduced to IPL in 1956 while at Dartmouth. The language had recursive functions, symbols, and lists built up from cons-like cells. Several notable programs were implemented in IPL, such as the General Problem Solver (Norvig 1991, ch. 4), the Logic Theory Machine, and the computer chess program NSS.

IPL programming involved machine language programming for the JOHNNIAC computer. An extension to FORTRAN with lists called FLPL was created for the IBM 704; it was used to prove theorems in plane geometry. The 36 bit word on the IBM 704 was divided into the 15 bit address, the 15 bit decrement, the 3 bit prefix, and the 3 bit tag. Because of this, linked lists were implemented in FLPL with car (Contents of Address part of Register), cdr (Contents of Decrement part of Register), and cons (Construct register).

McCarthy spent some time working on a chess program in FORTRAN in 1957, and the following year he worked on a program for differentiating algebraic expressions in FLPL. Based on his experience with these projects, he realized that a good AI language would need (1) conditional expressions, (2) recursive functions, and (3) implicit memory reclamation. The group at IBM which implemented FLPL was not motivated to add these features.

McCarthy was made an assistant professor at MIT in 1958, and with Marvin Minsky he founded the AI Project. Work began on implementation of Lisp for the IBM 704 that year. To reclaim memory, they decided on a garbage collector which could be invoked explicitly as reclaim. On paper, McCarthy was using what he called S-expressions for lists and M-expressions for function invocation:

(1,2,3,4)
append[(1,2);(3,4)]

The commas used for separating list elements would be optional in Lisp 1.5, and would be replaced by whitespace entirely in many later Lisp dialects. Additionally, the IBM 026 keypunch did not have square brackets, so S-expressions were used for function invocation as well; programs were run by passing S-expressions to eval:

(plus 3 (times 7 12))
(append (quote (1 2)) (quote (3 4))

Nested S-expressions were recursively treated as function invocations until a quote function was encountered.

TODO: evalquote and apply

TODO: maplist and higher order functions

TODO: lambda (church), prefix (polish) notation, turing completeness

TODO: label for recursion (vs y combinator), funarg problem, lexical closure

TODO: error handling and errset

In 1962 McCarthy left MIT for Stanford, where he established the Stanford AI Laboratory. However, Boston and MIT remained the center of Lisp development.

The PDP Era: 1963-1984

The Interlisp Programming Environment Teitelman 1981
Pitmanual: MacLisp Reference Manual Pitman 1983
Evolution of Lisp Steele 1993

For reasons including a patent dispute between MIT and IBM, Lisp development moved from IBM to DEC machines in the 1960s. L Peter Deutsch produced a Lisp for the PDP-1 in 1963 while at Bolt Baranek Newman. The PDP-1 memory typically consisted of 4k of 18-bit words, though in later years BBN had a PDP-1 with 8k-words of memory. The IBM 704 had 4k of 36-bit words per core memory unit. I haven't been able to discover how many core memory units the IBM 704 used by the MIT AI project had.

DEC produced two machines which were ideal for Lisp developement: the PDP-6 (1963), which in a typical installation had 32k of 36-bit words for memory; and the PDP-10 (1966), which was sold in memory configurations with anywhere from 32k to 256k of 36-bit words. A 36-bit word could represent a cons cell with two 18-bit memory pointers, and 256k is the maximum number of memory locations addressable by an 18-bit pointer. Most early Lisp interpreters were thus bound by a limit of 256k cons cells.

maclisp

MacLisp Manual 1976

  • macros
  • discontinuation of evalquote
  • readtables
  • err
  • ' for quote and ; for comment apparently

In 1964 members of MIT's Tech Model Railroad Club wrote a version of Lisp for the PDP-6. Project MAC was founded by a $2 million grant from Darpa in 1963, and the TMRC Lisp was the ancestor to the version of Lisp that was developed there.

bbn lisp and interlisp

The 1963 Lisp for the PDP-1 which Deutsch developed at BBN has been mentioned.

By 1966 BBN developed a 2nd version of Lisp for the PDP-1 as well as an upwardly compatible version to it for the SDS 940 computer. By 1971 they had a version for the PDP-10 called BBN Lisp which was upwardly compatible to the PDP-1 Lisp and the SDS 940 Lisp. By 1973 SDS was acquired by Xerox and development of the Lisp dialect became a joint responsibility of BBN and Xerox. The name of the dialect was changed to Interlisp by 1974.

The Interlisp community developed the convention that car and cdr always return a value which was nil in cases where the behavior was previously undefined.

In Lisp 1.5 three variants of the interpreter were developed: eval, evalquote, and apply. eval took a list as an argument. evalquote meanwhile took two arguments: a symbol denoting a function and a list containing the arguments to pass to the list.

(eval (quote (plus 1 2))
(evalquote (quote plus) (quote (1 2))

apply took three arguments: the function, the arguments to the function, and an environment which consisted of an associative array of variable to value mappings. The Lisp 1.5 apply was thus different from the modern apply which is identical to the Lisp 1.5 evalquote. The environment was necessary because of the use of dynamic binding in Lisp 1.5.

The Interllisp community favored evalquote over eval. An Interlisp REPL would be instructed to perform addition with a command like this:

plus (1 2)

Lisp Machines

A LISP machine with very compact programs Deutsch 1973
Lisp Machine Manual Weinreb 1981
CDR Coding
MIT CADR Lisp Machine Source Code 1980
User:Russell_Noftsker Noftsker
My Lisp Experiences and the Development of GNU Emacs Stallman 2002

Since they were running up against the addressable memory limits of the PDP-10, Richard Greenblatt started up a project at the MIT AI Lab to build machines that could execute Lisp efficiently. Thomas Knight did much of the initial design work, following ideas outlined by Deutsch in his paper on MicroLisp. The first of these machines, the CON, was prototyped in 1974 and went into production in 1976. It was followed by an improved model called the CADR.

A feature of the CONS and CADR Lisp machines was "CDR-coding". This was a performance improvement where the hardware replaced linked lists with contiguous memory in a way that was invisible to the Lisp program. This was made possible by the "tagged architecture" of the Lisp machines in which extra bits were available in words to indicate whether a cell contained a reference or a value directly. The result was faster access and a halving of memory use. On the downside the hardware would potentially need to copy to data when lists with shared sections were edited.

The Lisp machines at the suggestion of Deutsch replaced rplaca and rplacd with setf, and context aware versions of car, and cdr. See set-car and set-cdr.

The AI Lab produced and sold about 25 of the Lisp Machines by 1979 at a price of about $50,000 per unit. Configurations could vary but apparently the following were standard: black and white display, local hard disk, ethernet card, mouse and keyboard. The AI Lab wanted to see the machine manufactured in quantity. Greenblatt started the company LMI but most of the hackers at the AI lab joined Russell Noftsker who founded Symbolics, Inc. The company started selling clones of the CADR in 1981, and it introduced the Symbolics 3600 series of machines in 1983. In 1986 the company had $100 million in revenue, but Symbolics and other Lisp machines manufacturers went into decline in the 1990s as commodity PC hardware became the most price effective way to run Lisp.

Symbolics named the variant of Maclisp used by their machines "Zetalisp". Symbolics introduced licensing terms designed to protect their intellectual property rights. Stallman notes that business tactics like this brought an end to the hacker culture at the MIT AI Lab.

Portable Lisp

standard lisp (1969)

Standard Lisp Hearn 1969
The Standard Lisp Report 1979
Portable Standard Lisp for Cray X-MP Computers 1986

Standard Lisp was proposed by Hearn in 1969 so that packages like REDUCE would be portable.

The University of Utah released an implementation called Portable Standard Lisp in 1980. It compiled Lisp to LAP (Lisp Assembly Program, also used by MacLisp), and this in turn was compiled to C for portability.

Portable Standard Lisp was true to its name easy to port, but it lacked an interpreter and lexical scope (confirm); hence it disappeared as better implementations became available.

vlisp (1976) and le lisp (1983)

VLISP
Le Lisp

The Universite de Paris had a Lisp port as early as 1973, and a version of Lisp called Vlisp by 1976. To deal with the variety of hardware that Europeans had available at the time, Jerome Chailloux experimented with a virtual machine approach. He described the VCMC1 virtual machine in 1978.

Le Lisp was developed by Chailloux and colleagues at INRIA. It was described in an ACM article in 1984, and by that time it was running on 10 different architectures. The VAX version had performance comparable to Zetalisp on the Symbolics 3600. The first version of Caml was written for the LLM3 virtual machine used by Le Lisp.

franz lisp (1978)

History of LISP: Franz Lisp

A Lisp developed at UC Berkeley, originally for the VAX. It was implemented in C and ported to other architectures such as the Motorola 68000.

Common Lisp History

MacLisp and Interlisp users met at MIT in 1974. The MacLisp users adopted the behavior that (car nil) and (cdr nil) both evaluate to nil. The Interlisp users adopted read tables.

Meetings to define a single standard for Lisp called Common Lisp started in 1981. The standard was agreed upon in 1983, and Steele published "Common Lisp: The Language" in 1984. The CLOS standard was adopted in 1988. Common Lisp became an ANSI standard in 1994.

Scheme History

"A Universal Modular Actor Formalism for Artificial Intelligence" Hewitt 1973
SCHEME: An Interpreter for Extended Lambda Calculus Sussman 1975
The Original Lambda Papers Steele and Sussman

Scheme was initially implemented at the MIT AI lab in 1975 in MacLisp. It was a Lisp dialect with lexical scoping and closures; the motivation was a paper on actors by Hewitt.

Dates of Scheme reports:

RS (pdf) 1975
RRS (pdf) 1978
R2R2 (pdf) 1985
R3RS 1986
R4RS 1991
R5RS 1998
R6RS 2007

Clojure History

A recent dialect of Lisp that runs on the JVM. Clojure implements STM. Version 1.0.0 became available in May 2009.

Emacs History

Programming in Emacs Lisp
Emacs Timeline Zawinski 1999, 2007
My Lisp Experiences and the Development of GNU Emacs Stallman 2002
TECO Editor Wikipedia

In the late 60s and early 70s the MIT Lab ran the ITS operating system on PDP-6 and PDP-10 computers. The popular editor on the ITS was TECO, which initially this stood for Tape Editor and COrrector, but later was said to stand for Text Editor and COrrector. In 1972 Carl Mikkelson added real-time display editing capabilities to TECO, making it work more like vi than ed, to cite two Unix editors. Stallman added a macro capability to TECO in 1974. In 1976 introduced Emacs, which was originally implemented in TECO macros. Steele assisted in defining the command set for the new editor.

Emacs-like editors began to be ported to other machines. In 1978 a version of Emacs was written for the Multics operating system. It was implemented in Lisp and was the first version of Emacs to have Lisp as an extension language. EINE (Eine Is Not Emacs) and the later ZWEI (Zwei Was Eine Initially) were Lisp Machine implementations circa 1980. In 1981 Gosling wrote an implementation of Emacs in C which ran on Unix. It had an extension language called Mock Lisp which notably did not have linked lists.

Stallman began work on a C implementation of Emacs in 1984. The first widely used version was 15.34 released in 1985, one of the first products to come out of the GNU project. It had Lisp as an extension language. Although Lisp dialects were undergoing convergence as part of the work on Common Lisp, Common Lisp was too large a language to be embedded in an application in the 1980s. As a result Emacs Lisp is its own, simpler dialect of Lisp.

Emacs 18 was released in 1986. Emacs 19 promised improved GUI support but work proceeded slowly. Lucid was interested in releasing a suite of development tools which included Emacs as the text editor and they began contributing to the Emacs 19 effort. They had difficulty getting their changes accepted and ended up forking the code in 1992. The fork became known as XEmacs when Lucid shut down and Zawinski left for Netscape in 1994.

version release features
Emacs 19 1994 Emacs 18 Antinews
Emacs 20 1997 Emacs 19 Antinews
Emacs 21 2001 Emacs 20 Antinews
Emacs 22 2007 Emacs 21 Antinews
Emacs 23 2009 Emacs 22 Antinews

Historical Lisp Implementations

Lisp 1

Lisp 1 Programmer's Manual 1960

Lisp 1.5

Lisp 1.5 Programmer's Manual 1962

MacLisp

MACLISP Reference Manual 1976

Interlisp

INTERLISP Reference Manual 1973

Zetalisp

Lisp Machine Manual 4th ed 1981

Scheme

Scheme 1975
Scheme RRS 1978
Scheme R2RS 1985
T Manual (4th ed) 1984

Franz Lisp

Portable Standard Lisp

Le Lisp

Le Lisp 80 version 12.Le manuel de reference 1983

Open Source Lisp Dialects and Implementations

common lisp

scheme

  • Chicken compiles Scheme to C; almost R5RS
  • Gambit interpreter and Scheme to C compiler; R4RS and R5RS
  • Guile R5RS dialect designed for embedding in applications
  • Kawa framework for compiling "high-level and dynamic languages", including a near-R5RS Scheme, into Java bytecode
  • MIT/GNU Scheme the Scheme used by SICP; R5RS compliance forthcoming
  • Racket interpreter and compiler with extensive libraries; has R5RS and R6RS compliant versions
  • Scheme 48 R5RS Scheme with Regex, POSIX, and C FFI
  • SISC Scheme for JVM; R5RS
  • STk Scheme with Tk; development stopped in 1999; R4RS; replaced by STklos
  • STklos Scheme with Tk and CLOS-like extension; almost R5RS
  • TinyScheme small partial implementation of R5RS

other

  • arc new lisp dialect by Paul Graham with "optimal axioms"
  • Clojure JVM Lisp with immutable data structures and STM
  • emacs text editor with embedded Lisp
  • Lush C-extensible version of Lisp
  • newLISP C-extensible Lisp-1 with dynamic scope, runtime available and modifiable source, function arguments which are always optional, and fexprs for special forms
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License