a side-by-side reference sheet
grammar and invocation | variables and expressions | arithmetic and logic | strings | lists | arrays | dictionaries | functions
macros | execution control | file handles | files | directories | processes and environment | libraries and namespaces
objects | reflection | java interop | contact
| common lisp | racket | clojure | emacs lisp | |
|---|---|---|---|---|
| version used |
SBCL 1.0.48 | Racket 5.1 | Clojure 1.2 | Emacs 24.1 |
| show version |
$ sbcl --version | $ racket --version | displayed by repl on startup | $ emacs --version |
| grammar and invocation | ||||
| common lisp | racket | clojure | emacs lisp | |
| compiler | $ 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 | |
| shebang | #!/usr/bin/env sbcl --script | #!/usr/bin/env racket --script | specify full path to clojure jar: #!/usr/bin/env java -jar clojure.jar |
#!/usr/bin/env emacs --script |
| repl |
$ sbcl | $ racket | $ java -jar /PATH/TO/clojure.jar | M-x ielm |
| word separator | whitespace | whitespace | whitespace and commas | whitespace |
| are identifiers case sensitive? |
no | yes | yes | yes |
| identifier characters | everything except whitespace and: ( ) " , ' ` : ; # | \ reserved for user macros: ? ! [ ] { } |
everything except whitespace and: ( ) [ ] { } " , ' ` ; # | \ |
alphanumerics and these: * + ! - _ ? these have special meaning or are reserved: / . : |
everything except whitespace and: ( ) " , ' ` ; # | \ _ [ ] |
| escaping characters in identifiers | (setq white\ space\ symbol 3) | racket: (define white\ space\ symbol 3) |
none | (setq white\ space\ symbol 3) |
| quoting characters in identifiers | (setq |white space symbol| 3) | (define |white space symbol| 3) | none | none |
| end-of-line comment | (+ 1 1) ; adding | (+ 1 1) ; adding | (+ 1 1) ; adding | (+ 1 1) ; adding |
| multiple line comment | (+ 1 #| adding |# 1) | r6rs: (+ 1 #| adding |# 1) |
||
| variables and expressions | ||||
| common lisp | racket | clojure | emacs lisp | |
| label |
set,setq,defun | define | def,defn | set,setq,defun |
| quote |
quote | quote | quote | quote |
| cell types |
value, function, struct, class, … | value | value | value, function, struct, … |
| null | nil | null | nil | nil |
| null test | (null foo) | (null? foo) | (nil? foo) | (null foo) |
| is the empty list null? | yes | yes | no | yes |
| is null literal a symbol? | yes | yes | no | yes |
| 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) |
| keyword |
:foo | #:foo | :foo | :foo |
| arithmetic and logic | ||||
| common lisp | racket | clojure | emacs lisp | |
| true and false | t nil | #t #f racket: true false |
true false | t nil |
| falsehoods | nil () | #f racket: #f false |
false nil | nil () |
| is true a symbol? | yes | no | no | 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)) |
| relational operators | = /= < > <= >= | = none < > <= >= | = none < > <= >= | = /= < > <= >= |
| eq, equal, = | eq, equal, = | eq?, equal?, = | = works on symbols and is true for lists with identical members | eq, equal, = |
| min and max | (min 1 2 3) (max 1 2 3) |
(min 1 2 3) (max 1 2 3) |
(min 1 2 3) (max 1 2 3) |
(min 1 2 3) (max 1 2 3) |
| 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 |
| arithmetic operators | + - * / mod | + - * / modulo | + - * / mod | + - * / % |
| algebraic notation | ||||
| integer division and remainder |
(truncate 7 3) (rem 7 3) |
(quotient 7 3) (remainder 7 3) |
(quot 7 3) (rem 7 3) |
(/ 7 3) (% 7 3) |
| integer division by zero | arith-error | |||
| float division | rational: (/ 7 3) float: (/ 7 (* 3 1.0)) |
rational: (/ 7 3) float: (/ 7 (float 3)) |
rational: (/ 7 3) float: (/ 7 (* 3 1.0)) |
integer quotient: (/ 7 3) float: (/ 7 (* 3 1.0)) |
| float division by zero | -1.0e+INF, -0.0e+NaN, or 1.0e+INF | |||
| power | (expt 2 32) | (expt 2 32) | returns float: (Math/pow 2 32) |
(expt 2 32) |
| sqrt | (sqrt 2) | (sqrt 2) | (Math/sqrt 2) | (sqrt 2) |
| sqrt -1 | #C(0.0 1.0) | 0+1i | (Math/sqrt -1): NaN | -0.0e+NaN |
| transcendental functions | exp log sin cos tan asin acos atan atan | exp log sin cos tan asin acos atan atan | Math/exp Math/log Math/sin Math/cos Math/tan Math/asin Math/acos Math/atan Math/atan2 | exp log sin cos tan asin acos atan atan |
| float 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 |
| absolute value and signum |
abs signum | abs racket: sgn |
Math/abs Math/signum | abs signum |
| rational decomposition | numerator denominator | numerator denominator | (.numerator x) (.denominator x) |
none none |
| complex decomposition | realpart imagpart | real-part imag-part | none none |
none none |
| random number uniform 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 |
| random seed | ||||
| bit 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 |
| strings | ||||
| common lisp | racket | 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") |
| 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)) |
| 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 | racket | 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 |
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 |
| atom |
(atom x) | (not (pair? x)) | (not (list? x)) | (atom x) |
| (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) |
| sublis | (sublis '((1 . 2) (3 . 4)) '(1 (3 3 (1)))) |
(sublis '((1 . 2) (3 . 4)) '(1 (3 3 (1)))) |
||
| 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) |
| arrays | ||||
| common lisp | racket | 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 |
| 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 |
| dictionaries | ||||
| common lisp | racket | clojure | emacs lisp | |
| 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) |
| functions | ||||
| common lisp | racket | 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) (+ x y)) |
| 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 |
| lambda | (lambda (x) (* x x)) | (lambda (x) (* x x)) | #(* % %) (fn [x] (* x x)) |
(lambda (x) (* x x)) |
| 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)) |
| 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 |
| macros | ||||
| common lisp | racket | 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)))) |
| execution control | ||||
| common lisp | racket | 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")) |
| 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)) |
| 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) |
|||
| file handles | ||||
| common lisp | racket | clojure | emacs lisp | |
| standard file handles | *standard-input* *standard-output* *error-output* |
|||
| end-of-file behavior | read-line returns two values, the 2nd set to T at end-of-file. EOF-OF-FILE is signaled when reading past end of file. |
|||
| read line from stdin | (setq line (read-line)) | |||
| chomp | ||||
| write line to stdout | (defun println (s) (format t "~a~%" s)) (println "hello") |
(define (println s) (printf "~a~n" s)) (println "hello") |
(println "hello") | |
| write formatted 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) | |
| open file for reading | (setq in (open "/etc/hosts")) | (define in (open-input-file "/etc/hosts")) | (def in (java.io.BufferedReader. (java.io.FileReader. "/etc/hosts"))) | |
| open file for writing | (setq out (open "/tmp/test" :direction :output :if-exists :supersede)) | |||
| open file for appending | (setq out (open "/tmp/test" :direction :output :if-exists :append)) | |||
| close file |
(close in) | (close-input-port in) | (.close in) | |
| close file implicitly | (with-open-file (out #P"/tmp/test" :direction :output) (write-line "lorem ipsum" out)) | |||
| read line |
(setq line (read-line in)) | (define line (read-line in)) | (def line (.readLine in)) | |
| iterate over file by line | ||||
| read file into array of strings | ||||
| read file into string | ||||
| write string | ||||
| write line | ||||
| flush file handle | ||||
| files | ||||
| common lisp | racket | clojure | emacs lisp | |
| file test, regular file test | (osicat:file-exists-p "/tmp/foo") (osicat:regular-file-exists-p "/tmp/foo") |
(file-exists-p "/etc/hosts") (file-regular-p "/etc/hosts") |
||
| file size | (eighth (file-attributes "/etc/hosts")) |
|||
| is file readable, writable, executable | ||||
| set file permissions | (set-file-modes "/tmp/foo" #o755) | |||
| copy file, remove file, rename file | (cl-fad:copy-file #P"/tmp/foo" #P"/tmp/bar") (delete-file #P"/tmp/foo") (rename-file #P"/tmp/bar" #P"/tmp/foo") |
(copy-file "/tmp/foo" "/tmp/bar") (delete-file "/tmp/foo") (rename-file "/tmp/bar" "/tmp/foo") |
||
| create symlink, symlink test, get target | (osicat:make-link "/tmp/hosts" :target "/etc/hosts") | (make-symbolic-link "/etc/hosts" /tmp/hosts") returns target if symlink or nil: (file-symlink-p "/tmp/hosts") |
||
| temporary file | (make-temp-file "foo") | |||
| in memory file | (setq out (make-string-output-stream) (write-string "lorem ipsum) (get-output-stream-string out) (setq in (make-string-input-stream "dolor sit amet")) (read-line in) |
|||
| directories | ||||
| common lisp | racket | clojure | emacs lisp | |
| build pathname | (make-pathname :directory '(:absolute "etc") :name "hosts") |
|||
| dirname and basename | (pathname-directory #P"/etc/hosts") (pathname-name #P"/etc/hosts") |
(file-name-directory "/etc/hosts") (file-name-nondirectory "/etc/hosts") |
||
| absolute pathname | (expand-file-name "..") | |||
| iterate over directory by file | (dolist (file (osicat:list-directory "/tmp")) (format t "~a~%" file)) | (dolist (file (directory-files "/etc")) (print file))) |
||
| make directory | creates parents if 2nd arg non-nil: (make-directory "/tmp/foo/bar" t) |
|||
| recursive copy | ||||
| remove empty directory | (delete-directory "/tmp/foodir") | (delete-directory "/tmp/foodir") | ||
| remove directory and contents | (osicat:delete-directory-and-files "/tmp/foodir") | (delete-directory "/tmp/foodir" t) | ||
| directory test | (osicat:directory-exists-p #P"/etc") | (file-directory-p "/etc") | ||
| processes and environment | ||||
| common lisp | racket | clojure | emacs lisp | |
| external command | (run-program "ls" '( "/etc")) | (require scheme/system) (system "ls /etc") |
(.exec (Runtime/getRuntime) "ls") | (shell-command "ls /etc") |
| backticks | (shell-command-to-string "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") |
| libraries and namespaces | ||||
| common lisp | racket | clojure | emacs lisp | |
| load a file |
(load "a.lisp") | (load "a.rkt") | (load-file "a.clj") | (load-file "a.el") |
| load a library |
(require a) | (require 'a) | (load "a") | |
| list installed packages, install a package | (ql:quickload "osicat") | |||
| objects | ||||
| common lisp | racket | 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 | |
| reflection | ||||
| common lisp | racket | clojure | emacs lisp | |
| type-of |
type-of | none | type class | type-of |
| java interoperation | ||||
| common lisp | racket | clojure | emacs lisp | |
| new | (def rnd (new java.util.Random)) (def rnd (java.util.Random.)) |
|||
| method | (. rnd nextFloat) (.nextFloat rnd) (. rnd nextInt 10) (.nextInt rnd 10) |
|||
| class method |
(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
version used
Versions used to verify data in the cheat sheet.
show version
How to determine the version.
Grammar and Invocation
compiler
racket
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.
racket
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
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/bin/env emacs --script
(condition-case nil
(let (line)
(while (setq line (read-from-minibuffer ""))
(princ line)
(princ "\n")))
(error nil))
An implementation of echo:
#!/usr/bin/env emacs --script
(condition-case nil
(progn
(dotimes (i (length argv) nil)
(princ (nth i argv))
(princ " "))
(princ "\n"))
(error nil))
repl
How to invoke the repl from the command line.
racket:
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.
word separator
What is used to separate the operator and data of a S-expression.
are identifiers case sensitive?
Whether symbols are case sensitive. Common lisp is case insensitive, and as a result eq and EQ invoke the same function.
identifier 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.
racket:
# is only disallowed by the reader at the beginning of symbols. A symbol consisting of a single period must be escaped.
escaping characters in identifiers
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.
quoting characters in identifiers
end-of-line comment
multiple line 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)
)
Variables and Expressions
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.
type predicates
Some basic data type predicates.
nil, is () null?, is () symbol?
(eq nil ())
is true in common lisp and emacs lisp.
(eq? () null)
is true in Scheme.
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.
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.
Ten Primitives
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.
racket
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 | eighth | ||
| ninth | ninth | ninth | ||
| 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.
racket
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
true and false
Literals for true and false.
falsehoods
Values which evaluate to false in a boolean context.
common lisp
nil and the empty list () are identical.
racket
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.
is true a symbol?
logical operators
The logical operators.
relational operators
Relational operators for performing comparisions.
min and max
Functions for returning the least and greatest of the arguments.
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.
racket:
The following all evaluate as #t:
(rational? 1.1)
(rational? (sqrt 2))
(rational? pi)
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.
arithmetic 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.
transcendental functions
float 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.
racket:
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.
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.
racket:
The scheme/math library must be loaded to use sgn.
clojure:
Math/signum only operates on a float and returns a float
random number
How to generate a random integer, and a random float in a uniform and a normal distribution.
bit operators
racket:
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.
Strings
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.
racket:
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
racket:
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)))
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))))))
concat
split
join
format
regular expressions
common lisp
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
Lists
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.
racket:
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
racket:
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))
racket
(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)))
sublis
How to apply the mapping defined by an associative list to a recursive 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
racket:
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.
Arrays
vector literal
racket
#(1 2 3) creates an immutable vect. (vector 1 2 3) creates a mutable vector.
vector access
set vector element
racket
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.
range
list comprehension
Dictionaries
make hash
racket
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
racket:
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
Functions
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.
racket:
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.
Macros
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
Execution Control
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
racket:
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
racket:
- Unwind-protect vs. Continuations Kent Pitman
- Unwind-protect in Portable Scheme Dorai Sitiram
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
File Handles
standard file handles
end-of-file behavior
read line from stdin
chomp
write line to stdout
write formatted string to stdout
racket
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.
open file for reading
open file for writing
open file for appending
close file
close file implicitly
read line
iterate over file by line
read file into array of strings
read file into string
write string
write line
flush filehandle
Files
file test, regular file test
file size
is file readable, writable, executable
set file permissions
copy file, remove file, rename file
create symlink, symlink test, get target
temporary file
in memory file
Directories
build pathname
How to build a file pathname from components.
dirname and basename
How to extract the directory portion of a pathname; how to extract the non-directory portion.
absolute pathname
How to get the get the absolute pathname for a pathname. If the pathname is relative the current working directory will be appended.
iterate over a directory by file
How to iterate over the files in a directory.
make directory
How to create a directory, including any parents directories specified in the path.
recursive copy
How to copy a directory and its contents.
remove empty directory
How to remove an empty directory.
remove directory and its contents
How to remove a directory and its contenst
directory test
How to test whether a directory exists.
Processes and Environment
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
Libraries and Namespaces
loading a file
How to load a file and evaluate the top level expressions.
common lisp
Does not display the result of any evaluations.
racket
Displays the result of the last evaluation.
loading a library
Objects
define class
make instance
read attribute
write attribute
define method
invoke method
define subclass
universal superclass
multiple inheritance
Reflection
type-of
How to get the data type of the entity referred to by a symbol.
Java Interoperation
version used on jvm
extra libraries used
racket:
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
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")
Racket
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
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.