Command history
In Linux, if you want to have command history when in the REPL, e.g. the use of up/down to scroll between previously entered expressions, then you can launch sbcl via rlwrap. Add the following to ~/.bash_aliases:
alias lisp='rlwrap sbcl'
(Be sure to source it with source ~/.bash_aliases
)
Now when you launch lisp
you should have command history.
FORMAT
Use t as second argument to have FORMAT print to stdout. Use nil to have it return a string. Use of ~a
in the format string will have FORMAT format its arguments in an “aesthetic” (i.e. human readable) form.
CL-USER> (format t "~a" "test")
"test"
CL-USER> (format t "~a" 'test)
"TEST"
CL-USER> (format t "~a" 3)
"3"
~%
gives you a new line:
CL-USER> (format nil "~a~%" "test")
"test
"
CL-USER> (format nil "~a~%~a" "foo" "bar")
"foo
bar
"
Nested loops
To return from a nested loop you need to name the outer loop and use return-from:
CL-USER> (loop named outer for i in '(1 2 3) do
(loop for j in '(5 2 7)
when (equal i j) do (return-from outer i)))
2
Packages
*package*
defines the current package.
(package-name *package*)
returns the name of the current package.
Packages and EQ
EQ doesn’t work when comparing symbols from two different packages. For example, if you have a function in a custom package that returns a dispatch function closed over a variable, then calling EQ from the dispatch function will not work:
(defpackage :test
(:use :cl)
(:export :make-test :make-another-test))
(in-package :test)
(defun make-test ()
(lambda (m)
(eq m 'foo)))
(setq test (funcall #'test:make-test))
(funcall test 'foo) ; --> T
(funcall test 'bar) ; --> NIL
(in-package :cl-user)
(setq test (funcall #'test:make-test))
(funcall test 'foo) ; --> NIL
(funcall test 'bar) ; --> NIL
The easist way around this is to use keyword symbols, which begin with a colon rather than a quote, as follows:
(in-package :test)
(defun make-another-test ()
(lambda (m)
(eq m :foo)))
(in-package :cl-user)
(setq another-test (funcall #'test:make-another-test))
(funcall another-test :foo) ; --> T
(funcall another-test :bar) ; --> NIL
Macroexpand
CL-USER> (defmacro m (x) `(* ,x 3))
TM
CL-USER> (m 2)
6
CL-USER> (macroexpand '(m 2))
(* 2 3)
T
Keywords
Use intern
to create a keyword from a string. This can be useful inside macros where you want a keyword created from the output of a function.
(intern (write-to-string (+ 2 3)) :keyword) -> :|5|
Note the pipe characters (bars) in the resulting keyword. This shows the difference between the use of upper and lowercase:
(intern "foo" :keyword) -> :|foo|
(intern "FOO" :keyword) -> :FOO
Arrays
In order to make an empty array you have to set the initial size to at least 1 and use the fill-pointer keyword, as follows:
CL-USER> (setf a (make-array 1 :fill-pointer 0))
; ...
#()
CL-USER> (vector-push 'foo a)
0
CL-USER> a
#(FOO)
Here are some examples of what won’t work:
CL-USER> (setf a (make-array 0))
; ...
#()
CL-USER> (vector-push 'foo a)
; Evaluation aborted on #<TYPE-ERROR ...
CL-USER> (setf a (make-array 1))
; ...
#(0)
CL-USER> (vector-push 'foo a)
; Evaluation aborted on #<TYPE-ERROR ...
CL-USER> (setf a (make-array 0 :fill-pointer 0))
; ...
#()
CL-USER> (vector-push 'foo a)
NIL
CL-USER> a
#()