Lisp (SBCL) notes

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
#()

References

Last modified: 20/01/2014 Tags: ,

This website is a personal resource. Nothing here is guaranteed correct or complete, so use at your own risk and try not to delete the Internet. -Stephan

Site Info

Privacy policy

Go to top