Saturday, March 24, 2012

CLISP cheatsheet

A quick-'n'-dirty crib sheet of the GNU Common Lisp programming language, a pragmatical non-minimalist LISP implementation. This is limited to the contents of the wonderful introductory book Land of Lisp and some of the information is paraphrased from this book. Therefore this page is meant to complement the book, since it lacks a reference of the commands, which are introduced in a scattered way.

Integrated development environment


To learn the language, using the REPL or executing Lisp programs saved in text files on the command line is enough. As for documentation, begin with using this simplified reference if the full official standard seems too much stuff for a newbie. Anyway, as you write more and more complex and long Lisp programs, you may find inconvenient and slow to have to continually save a whole Lisp file in your editor of choice and then run it with the Lisp interpreter. Lisp is dynamic in nature and allows you to make a modification to a program and test it immediately. You can even redefine a form!

If you already use the Emacs editor, go for Slime. If you know the VIM editor well there is Slime clone for it called Slimv. If you know neither Emacs nor VIM, I recommend Geany along with the handy LispEdit plugin.

I personally use both Geany and Slimv because I already know VIM and am too lazy to learn another editor like Emacs well. I maintain the Slimv Arch Linux package too. Here is a very useful Slimv tutorial. And a table of Slimv main keyboard shortcuts to get you started in no time:

command action
,c Connect to LISP and show the REPL
<Ctrl-w>w switch between the REPL window and the source code window
,s Describe the symbol under cursor, just like (describe 'symbol)
,h look up the symbol under cursor in the Common Lisp Hyperspec
,d Evaluate the current top-level form
,e Evaluate the current form
,g Set the current package by entering its name
= Indent selected forms
,W or ,w( Wrap current symbol or form inside parens. ,w" for wrapping it in double quotes.
,S Removes outer pair of parens from current symbol or form
,O Splits current string/form into two
,J Joins the two string/form to the left and to the right into one
,> or ,< Move parens to the Right or Left
,F Compile the file
,L Compile and load
,i Like (inspect 'symbol), symbol is the current symbol under the cursor by default
,1 Expand current macro, just like macroexpand-1
,t Toggle tracing for the function name under the cursor, just like (trace function)
,T Untrace all traced functions
Shortcuts available when debugging is activated:
command action
,a Abort restart
,a or ,q or ,n Abort or Quit or Continue restart

If you are confused about the concepts of packages, systems, modules as they apply to Lisp, read this explanation.

conventions and best practices


Naming conventions: functions that return nil or a truth value are called predicates and have a 'p' appended to the end of their name.

Avoid using any function that ends in not. They are considered deprecated and may be removed from future versions in the ANSI Common Lisp standard.

To describe a computation you don't want to run until later (a delayed computation), create a nullary function, that is a function that has zero arguments aka a thunk or a suspension:

(lambda () ...)

E.g. to ease debugging you may want to output to the console, even if output should be directed to a file on disk, the network, etc. You can then wrap the output stuff as a thunk and pass it to another function that calls the thunk, captures the results and sends them to another location (e.g. a file).

read-eval-print loop (REPL)


$ clisp
:q
(quit)

basic data types and operators


Both data and code in Lisp is represented with syntax expressions. In this format, data is represented using nested lists, often with Lisp symbols at the front of each list explaining the structure of the data.

symbols (case-insensitive): any combination of letters, numbers and + - / * = < > ? ! _. Indeed any character othen than ( ) # ' ` whitespace is permitted in a symbol, provided that a symbol does not take the form of a number
symbols (case-sensitive): ditto, but surrounded by vertical pipes. E.g. |Hello!|

keyword symbols: :symbol
A colon-prepended symbol always means itself. It is a constant that evaluates to itself. E.g. used for keyword parameters. Use a keyword symbol every time you know a symbol just has a meaning in its own right.

cons-cell (or "pair"): (cons slot1 slot2) or '(slot1 . slot2)
A pair is a dotted list consisting of two elements only, that is of length two. E.g. useful to store the x- and y-coordinates of a point or a key/value.

lists: (elem1 ... elemn) or (cons elem1 (... (cons elemn ())...) or (list elem1 ... elemn)
List recursive definition: a list is either empty, that is () or nil or a cons whose car is the first element of the list and whose cdr is a list containing the rest of the elements.
elements can be of any Lisp datatype. This implies that the right slot in the last cons cell in a list must contains a nil. E.g. a list of characters is defined as: '(#\! #\? #\.)
This is just a shortcut for creating and display a list, but it always remains a chain of cons cells.

dotted lists: (cons elem1 (... (cons elemn-1 elemn)...) or '(elem1 . (... (elemn-1 . elemn)...)
They are lists that end in something other than a nil. Both dotted and proper list can be created using the dot notation as well, although the bracket syntax for lists is the simplest.

circular lists: they are lists where the last cons cell points to an earlier cons cell in the same list.
This is required for CLISP to be able to print self-referential data structures without getting into an infinite loop:
(setf *print-circle* t)

(defparameter list '(1 2 3))
(setf (cdddr foo) foo)
output: #1=(1 2 3 . #1#)

form: (command arg1 ... argn)
Before the function command is evaluated, all the expressions after the function name are evaluated.

empty command, return nil: ()

fractions: signed-int-numer/int-denom

strings: "Hello \"World\""
Note: storing text as a list of symbols instead of a string often makes it easier to manipulate. But beware of commas, since they are unsupported in symbols. A solution to represent them would be to just fall back on using text strings, e.g. '("Welcome," visitor) and then strip the quotation mark afterwards when processing.

characters: #\a
Literal characters are prefixed by the symbol #\. Special literals are defined for nonvisible chars. E.g. #\newline, #\tab, and #\space.

data mode: 'data or (quote data)
data should be a piece of code you want to treat as data

quasiquoting: `...data...,(command ...)...
This facility allows you to build a piece of data out of function results and some static data, by interpolating command results. E.g. it is a handy way to insert small bits of computer code into larger pieces of data.

nil is a constant that evaluates to itself

boolean values: any empty list '() () 'nil nil is false
everything else is true, including the pre-defined constant t (or T)

#'fun or (function fun)
function operator. Just a shorthand for the function operator. In CLISP must be used to pass a function as argument to another function. Its purpose is to avoid conflicts between the function name and possible variables named the same way. Common Lisp tracks function names differently from variable names. It has multiple namespaces, including one for variables and one for functions. Conversely Scheme has only one namespace for both functions and variables.

(coerce arg 'type)
E.g. to convert a string to a list of chars: (coerce "hullo" 'list) -> (#\h #\u #\l #\l #\o)
to convert a list to an array: (coerce '(one two three) 'array) -> #(ONE TWO THREE)

(lambda (optional args) body)
Define an anonymous function and returns it as a value. There's no need to give the function a name. Note lambda itself is not actually a true function. It is a macro since not all its parameters of the lambda command are evaluated before the function itself is evaluated. The lambda macro allows you to package up an ad hoc function and pass it off to another function of your program that accepts functions as parameters. This technique is called high-order functional programming.

#(elem0 elemn-1)
Zero-based array

#S(HASH-TABLE :TEST FASTHASH-EQL (key1 . value1) (key2 . value2))
Hash table. :TEST specifies the function used to test the equality of keys. Use EQUAL if you want string and not symbol to be the key type. For case-insensitive string hashing use EQUALP.

(type-of expr)
Finds the type of any Lisp value.

t
Although all non-nil values are considered true, by convention the constant t is usually used to represent truth.

globals


redefinable: (defparameter *var* val optional-documentation-string)
non-redefinable: (defvar *var* val)

earmuffs *...* are optional but recommended

cell/list manipulation forms


add elem to the front: (cons elem list)
first elem/slot: (car cell) or (first cell)
car is an old name for first. The name stands for "Contents of the Address Register" the instruction that was used to implement car on the IBM 704, the computer where Lisp was first implemented.

rest/second slot: (cdr cell) or (rest cell)
cdr = Contents of the Decrement Register

(cadr list) or (car (cdr (list)) or (second list)
(cdar list) or (cdr (car (list))
(cadadr list) or (car (cdr (car (cdr list)))) etc.
up to four levels deep all car/cdr combinations are pre-defined
functions to directly access single elements are defined from first to tenth

(last list n)
Returns a list of the last n elements of list, where n defaults to 1.

(nth unsigned-int-index list)
Zero-base indexing on lists. Warning: slow on large lists, use arrays and the aref function instead.

(length sequence)
(list-length list) is a bit faster but only works on lists.

(append list1 ... listn)
Joins lists.

(push item list) or (setf list (cons item list))
Adds item in front of a list variable. Modifies and returns the new list variable.

(pushnew item list)
Same as push, but item is added only if does not already exists in the the list variable.

(find item list :key #'func)
Searches list for item and returns the element that contains item or nil if not found. Optionally you can provide a special keyword parameter named :key to indicate the location where to find key values to compare item with. E.g.: (find 4 '((1 2) (3 4)) :key #'cadr) returns (3 4)

(member elem list)
Returns the tail of the list starting with elem or nil. elem can be nil, since the LISP list recursive definition allows nil values everywhere in a list, not only at the end. elem can be of any Lisp datatype, of course.

(find-if #'func sequence)
High-order function. Returns the first value in the sequence for which func returns true or nil, that is finds the first value that satisfies a predicate. There is no way to find a nil value in list: using null as func, nil is returned both if a nil value is present and not present in list.

(mapcar #'func list)
High-order function. Applies func to every member of list and returns the list of results. Same as map in Scheme.

(mapcar #'func list1 ... listn)
If three or more arguments are passed to mapcar, #'func should be an n-ary function, which will be applied to corresponding elements of the lists list1 ... listn, until the shortest list is exhausted.

(maplist #'func list)
High-order function. This is like the mapcar function, except that the function inside it (func) receives the entire remainder of the list, not just the current item in the list. The first call of func receives the entire list, the second the cdr, the third the cddr, and so on till the last call which receives a list comprising the last element of the list only.

(mapc #'func list)
High-order function. Applies fun to every member of list. More efficient than mapcar in that it does not return the transformed list but the original list. Anyway func can actually do something with every element of the list, e.g. producing some side-effects like outputting the value. In other words, use mapc in places where you care only about the side effects and don't care about generating a final list as a result.

(mapcan #'func list)
Variant of mapcar. It assumes that the values generated by the mapping function #'func are all lists that should be appended together. This is useful when there isn't a one-to-one relationship between the items in a list and the result you want to generate.

(apply #'func list)
High-order function. Invokes func passing each element of list as the function arguments. A maximum of 4096 arguments are supported (this is the value of the global predefinite constant call-arguments-limit). E.g.:

(apply #'append '((one two) (three four))) evaluates to (ONE TWO THREE FOUR)
just like (append '(one two) '(three four))
while
(append '((one two) (three four))) remains the same list: ((ONE TWO) (THREE FOUR))

(funcall func arg1 ... argn)
Calls func with arguments arg1 ... argn. Useful when the name of the function to call is in a variable.

(remove-if-not #'func list)
High-order function. Removes all things from a list for which a passed-in function doesn't return true. Essentially, it returns a filtered list of objects consisting of those items for which func is true.

(set-difference list1 list2)
Returns all items that are in list1 but not list2, in the order they appear in list1 that is it preserves order.

(intersection list1 list2)
Returns all items shared between list1 and list2, nil if none.

forms for abstraction and combination


function def: (defun function_name (optional arguments) "optional documentation string" body)
The last expression is returned as the value of the function call. User functions can be redefined at runtime in Lisp, just like variable values can be changed. Redefining predefined functions works as well, but makes CLISP to issue a warning message.

overloaded statically-typed function def: (defmethod function_name ((arg1 type1) ... (argn typen)) body)
The defmethod function is like defun, except that it allows us to write multiple functions with the same name. When using defmethod, we can explicitly state the type of each parameter in the function's argument list so that Lisp can use these type declarations to figure out the correct version to call for each situation.

returning multiple values: (values expr1 ... exprn) or just return a list (slower)
first value expr1 will be used by default during follow-up calculations, expr2 to exprn will be ignored unless you bind them to variables using: (multiple-value-bind (var1 ... varn) expr-returning-multiple-values body) body means there is an implicit progn

local vars: (let ((var1 val1) ...(varn varn)) body)
Each var will be a lexical, local variable but if a dynamic variable already exists with the same name, let will instead, temporarily, override the value of the dynamic variable to the new value. You may find annoying that you need a parenthesis around each bind when giving the starting value. This syntax has been chosen to group variables and values better visually. It also allow you to omit nil when you want to define a variable but not initialize it. E.g. (let ((var1) (var2 value2)) ...) is equivalent to (let ((var1 nil) (var2 value2)) ...).
(let* ((var1 val1) ...(varn varn)) body)
Same as let but allows you to refer to previously defined variables when assigning the value of a subsequent variable.

local functions: (flet ((fun1 (arg1) body1) (fun2 (arg2) body2)) body)
local functions that can call themselves: (labels ((fun1 (arg1) body1) ... (funn (argn) bodyn)) body)
list def: (list elem1 ... elemn)

code block: (progn expr1 .. exprn)
Evaluates all arguments but returns only the value of the last one as the value of the full expression. Not to abuse in a functional programming style.

(eval data)
Evaluates LISP data as code. Allows to write a program with self-modifying code. Not to be misused or be used instead of macros. Since eval allows you to call any Lisp command, for security do not trust and double check any data read from external sources you don't trust that are going to be evaluated.

(concatenate 'datatype expr1 .. exprn)
Concatenates strings or other types of sequences.
E.g. (concatenate 'string "Hello " "World") returns "Hello World"
(concatenate 'list '(1 2) '(3 4)) produces (1 2 3 4)

forms that produce side-effects


(setq var value)
Set Quantity. setq can assign only to variables. In the majority of cases, the special evaluation of a generalized-reference isn't needed, so you're probably slightly better off (in terms of performance) by using setq. If you get it wrong, LISP will kindly remind you, so you can then still use setf instead when required.

(setf generalized-reference value)
setf (set field) supports generic setters. generalized-reference can not only be a variable. It can be any code for pulling a value out of a data structure (whether an array, list, string, or something else) that can be used for putting data into the same structure. setf is a macro which builds on setq.

(incf generalized-reference inc-number)
inc-number defaults to 1

(decf generalized-reference dec-number)
Variant of setf that subtracts an amount dec-number from the variable generalized-reference. dec-number defaults to 1

To decrement/increment use the built-in "+" or "-" functions, or their shorthand "1+" or "1-", if you just want to use the result, without modifying the original number (the argument). If you do want to modify the original place (containing a number), then use the built-in "incf" or "decf" functions.

forms for flow control (conditionals)


(if cond then-expr optional-else-expr)
The optional-else-expr defaults to nil.
It's a special form in that only one of the expressions after the if is actually evaluated.

(when cond expr1 ... exprn) or (if cond (progn expr1 ... exprn))
Does nothing and returns nil if cond is false

(unless cond expr1 ... exprn) or (if (not cond) (progn expr1 ... exprn))
Does nothing and returns nil if cond is true

(cond (cond1 expr11 ... expr1n) ... (condn exprn1 ... exprnn) (t def-expr1 ... def-exprn))
Conditions are checked in the order cond1 ... condn. An optional special condition t (for true) can provide a default case.

(case expr ((expr1) expr11 ... expr1n) ... ((exprn) exprn1 exprnn) ... (otherwise def-expr1 ... def-exprn))
It could be more efficient but it is limited to eq for comparisons. Therefore it can usually used only for branching on symbol values.

(dolist (var list result) ...)
Executes the body once for each element in list, with var bound to the element. Returns nil if there is no result form, otherwise evaluates and returns the value of this form.

(do ((var1 val1 update1) ...(varn valn updaten)) (termination-predicate [return-value]) ...)
Binds var1 ... varn to their initial value val1 ... valn respectively. If termination-predicate is false, execute body and update var1 ... varn by executing update1 ... updaten respectively and loop again; when termination-predicate becomes true, return the value of return-value.

(loop ...)

This is a very powerful and flexible macro for all your looping needs. It's parameters or tokens are interpreted as a small language. You can use almost any meaningful combination of the following clauses:

expr1 ... exprn
Loops forever. You'll need to hit CTRL-C and type :a to get out of the infinite loop.

repeat number
Loops number times

for n [from number1] [below/to number2]
Declares a variable n that iterates through a range of values, namely from number1 (0 by default), incrementing n by 1 until n <= number2 (to) or n < number2 (below. number2 is infinity by default.
Use it in case you need to keep a running count as you're looping. You can use more than one for clause: variables are incremented in parallel. The loop will stop when any one of the clauses runs out of values.

for n in list
Iterates through values in list.

when (predicate)
Runs the following part of the loop only under the condition predicate

return expr
Breaks out of a loop and returns expr

sum expr
Adds together all values of expr and makes the loop return that number

collect expr
Collects the values of expr into a list that returns

do expr1 ... exprn
Executes arbitrary expressions inside the loop

Some good examples are here: http://www.unixuser.org/~euske/doc/cl/loop.html

boolean forms


(and expr1 ... exprn)
Returns exprn if all expressions evaluate to true, else nil. Stops evaluation at the first false expression.

(or expr1 ... exprn)

CLisp uses shortcut Boolean evaluation. This allows one to use boolean forms as some kind of conditionals. E.g.:

(if cond1 (if cond2 expr)) or (and cond1 cond2 expr) or, clearer but not so short: (if (and cond1 cond2) expr)

(complement #'func)
High-order function. Creates the opposite (or complement) function to func.

comparing forms


Rule of thumb: use eq for comparing symbols because it's faster, equal for everything else.

(eq sym1 sym2)
Compares symbols for equality. Preferable to equal when comparing symbols.

(equal thing1 thing2)
Compares two things for isomorphism, meaning they "look the same". It works for any datatype: symbols, lists, integers, floating point numbers, strings, characters.

(eql thing1 thing2)
Compares symbols, numbers and characters for equality.

(= number1 number2)
Same as equal, but limited to numbers.

(string= string1 string2)
Same as equal, but limited to strings.

(string-equal string1 string2)
Same as string= but differences in case are ignored.

(char-equal char1 char2)
Same as equal, but limited to chars.

(equalp thing1 thing2)
Same as equal, but loose comparison: case-insensitive for strings, same value for intergers and floating-point numbers.

(null expr)
Returns true for any of the nil values: () '() nil 'nil. False otherwise.

(zerop number)
Returns true if number has the value 0, nil otherwise

(numberp expr)
Check whether expr is a number

(consp expr)
Check whether expr is of type cons

(arrayp expr)
(characterp expr)
(consp expr)
(functionp expr)
(hash-table-p expr)
(listp expr)
(stringp expr)
(symbolp expr)

math forms


basic operators: + - / *
increment: (1+ num)
decrement: (1- num)

arithmetic shift: (ash signed-int signed-int-position)
Positive positions shift to the left, negative ones to the right

exponentiation: (expt num-base num-exponent)
(oddp signed-int)
(evenp signed-int)
random integer in the interval [0..num), that is from 0 to n-1: (random num)
round off numbers: (round number) returns both the integer part and the remainder
(max expr1 ... exprn)
(min expr1 ... exprn)
(truncate expr)

I/O forms


Some of these functions can accept a stream as an optional parameter. In this case, these printing functions won't print anything to the console, but instead will print to the stream object.

For computers


(print arg stream)
Prints objects in such a way that they can always be "read" back into their internal representation. Therefore it can't be used to generate any arbitrary bit of text. Use princ for that. It starts a newline before printing arg and places a space character at the end of the printed value. LISP code is printed just as it is, e.g. strings are printed with double quotes but functions cannot be printed. Symbols are printed in all caps. Put an explicit quote on the front of a symbol to not get it mixed up with functions of the same name.

(prin1 arg stream)
Same as print but it only prints arg, no newlines or spaces. The 1 means will stay on a single line.

(prin1-to-string arg)
Same as prin1 but doesn't dump the result to the screen, just returns it as a string. E.g. it can be used for converting a list into a string:
(prin1-to-string '(1 2)) yields "(1 2)"
prin1-to-string acts like write-to-string with :escape t, that is, escape characters are written where appropriate

(write-to-string arg :keyword_parameter value...)
It is the general output function. It has the ability to specify all the parameters applicable to the printing of object. E.g. :pretty nil tells Lisp not to alter the string to make it pretty. Without this, Lisp would place new lines or tabs into our converted string to make it look more pleasing to the eye.

(read stream)
Reads LISP code from stream (by default stdin). E.g. the user will have to type quotes around a string. Security: beware that the user can use reader macros to execute a command by inputting #.{command}

(read-from-string string)
Just like (read) but reads a syntax expression (or any other basic Lisp datatype) from string instead of directly from the console.

For humans


(princ arg stream)
Prints any LISP data. E.g. strings are printed without double quotes, characters in their raw form, etc. Symbols are capitalized.

(read-line stream)
Returns all the text entered until the ENTER key is pressed as a string on the console or a newline is encountered on another kind of stream.

(fresh-line stream)
Makes sure that the next item appearing on the screen/stream will start on a fresh line.

(princ-to-string arg)
princ-to-string acts like write-to-string with :escape nil :readably nil. Thus no escape characters are written.

Streams


Example of opening a file for writing. It creates a locally-scoped (lexical) stream variable my-stream and connects it to an output file (use :if-exists error to prevent overwriting; use :direction :input for the opposite behaviour):

(with-open-file (my-stream
"filename.txt"
:direction :output
:if-exists :supersede)
....body has my-stream defined...))

Use one of the default streams (special global variables) as my-stream to redirect output:

*standard-output*

string functions


(string-trim charliststring string)
Strip some characters from the beginning and end of a string (not the middle).

(string-upcase string)

generic functions


Generic functions can accept multiple datatypes as parameters and handle them appropriately.
E.g. sequences are either lists, strings or vectors (arrays), the three main ways of sequencing objects in Lisp. String components are characters, lists or array ones are elements.

(substitute-if value #'func sequence)
Substitutes each occurrence of value in sequence based on the result of the test func.

(subseq seq start-index end-index)
Returns a subsequence of seq from start-index (included, 0-based) to end-index (not included). If end-index is omitted, it defaults to the sequence length.
E.g. subseq can be used to extract substrings: (subseq "I don't believe it" 2 7) returns "don't"

(remove-duplicates sequence :keyword_parameter value...)
Removes duplicate items from a sequence. By default it uses the eql function to check for equality. Use the :test keyword parameter to choose a different test function.

(some #'func sequence)
Returns the first non-nil value which is returned by an invocation of the predicate #'func. If the end of a sequence is reached without any invocation of the predicate returning true, some returns nil (that is false). Thus, some returns true if and only if some invocation of predicate returns true, that is if any items in sequence satisfy the predicate #'func.

(every #'func sequence)
See if every value in sequence obeys a specific predicate #'func.

(reduce #'func sequence :keyword_parameter value...)
Iterates through a sequence and distills it down into a single result. The first number in the list we're reducing will be used as a starting value, since #'func must be a dyadic operator. If this is a problem, we can instead pass an explicit initial value to the reduce function by passing in a keyword parameter named :initial-value.

(reverse sequence)

(map type #'func sequence)
Identical in behavior to mapcar, but works on all sequence types, not just lists. You specify the type of sequence to return from the mapping by passing an extra argument type

(sort sequence #'func)
Sorts a sequence according to the binary predicate #'func

character functions


(char-upcase char)
(char-downcase char)

(digit-char-p char)
Tells us if a character is a numerical digit

(alphanumericp char)
Tells us if a character is alphanumeric

(count elem sequence)
Finds out how often a certain object elem appears in sequence.

(position elem sequence)
Tells you where an item elem is located in sequence, starting the count from zero (zero-based index).

Association lists (alists)


Alists are lists of pairs. They can be used to store data that is in the form of keys associated with values, when you want to lookup a key and find the information associated with that key.

Drawback: not very efficient. Use only for very short lists (under a dozen items), else use real hash tables.

((key1 ...) ... (keyn ...))
... is a value, any data type. By convention, if a key appears multiple times in the list, it is assumed that the first appearance of the key contains the desired value.

((key1 . value1) ... (keyn . valuen))
Alternative definition of an alist as a list of pairs instead of a list of lists. assoc works with both definitions.

(assoc key alist)
Searches alist from the beginning for the first occurrence of the desired key. Returns a list/pair like (key ...) or (key . value) if key is found - that is it returns both the key and the value from the alist, nil otherwise.

(push item alist)
A common tecnique to replace a value from an alist is to push new items onto the list since only
the most recent value will be reported by the assoc function. This also maintains a history of all old values.

Arrays


The Common Lisp array is very similar to a list. The main advantage of using
arrays is that they require only a constant amount of time to access a value at
any specific location. Array indexing is zero-based as in C.

(make-array unsigned-int-dimension :keyword_parameter value)
Creates and returns an array of specified length, filled with nils, unless the :initial-content list parameter is used.

(aref array-var index)
Gets the index-th element out of array-var.

(setf (aref array-var index) val)
Sets the index-th element of array-var to val

Hash tables


Like alists, hash tables store items using a lookup key and a value, but more efficiently. Anyway, alist remain more efficient for small tables.

(make-hash-table)
Creates a new empty hash table

(gethash key hash-table)
Get a value out of hash-table. Actually returns two values: the first returned value is the actual value stored in the hash table or nil, and the second indicates whether the key was found in the table (nil or t)

(setf (gethash key hash-table) val)
Store val into hash-table with a lookup key of key

Structures


Structures encode objects with multiple properties, typically data that needs to be mutable. They can be simulated using lists, but this approach requires writing more code, is less readable and slower when you change the state of the objects. You have to depend on order to interpret property values and there is no type attached, unless you add one.

Thanks to the print/read symmetry in Lisp, you can create a structure directly from the printed representation of a structure:

#S(TYPE :PROPERTY1 value1 ... :PROPERTYN valuen)

but TYPE must be previously defined using:

(defstruct type property1 ... propertyn)

property can be a field name or a list (field-name expr), where expr is a form that will be evaluated when a new structure of type type is created and returns a default value for that slot.
type can be a type name of a list (type-name (:include parent-struct-type-name)) to include all the fields of another structure.

defstruct also defines a special function for creating instances:

(make-type :property1 value1 ... :propertyn valuen)

and a bunch of accessors/setters (usable with setf):

(type-property1 struct-var)
...
(type-propertyn struct-var)


Debugging


(trace func1 ... funcn)
(untrace func1 ... funcn)
Special forms to turn off and on tracing for func1 ... funcn. Tracing information will be printed if and when the functions are called.

(ed 'function-name)
Opens the default editor to interactively edit function-name definition. This function must already be defined before.

Profiling


(time expr)
Prints various timing data and other information to trace output, such as elapsed real time, machine run time, and storage management statistics

(dotimes (var number) body)
Run a chunk of code (body) number times.


Working with sockets

CLISP has its own socket library, but it is not standard. For more portatibility, I recommed using the USOCKET library.  Here is how the manual simulation of a TCP/IP client-server socket connection, using two REPLs:

ON THE SERVER

; Install, load and import the usocket library
(ql:quickload :usocket)
(use-package :usocket)

(defvar server-socket (socket-listen "localhost" 4321))

(class-of server-socket)

; This blocks, waiting for connections
(defvar connected-socket (socket-accept server-socket))

(class-of connected-socket)
(defvar connection-stream (socket-stream connected-socket))

(read connection-stream)

(print "Ave Client!" connection-stream)
(force-output connection-stream)

; This frees port 4321
(socket-close server-socket)

ON THE CLIENT

(ql:quickload :usocket)
(use-package :usocket)

; Create a connection to localhost or #(127 0 0 1)
; Replace with your server host name or IP address, if you have two machines.
(defvar client-socket (socket-connect "localhost" 4321))
(class-of client-socket)

; Convert the socket to a stream so we can easily read from it or write to it.
(defvar connection-stream (socket-stream client-socket))
(class-of connection-stream)

(print "Ave Server!" connection-stream)

; Output is buffered for efficiency reasons! this forces it to be sent.
(force-output connection-stream)

; This blocks until data are available or the connection drops
(read connection-stream)

; This flushes connection-stream too.
(socket-close client-socket)

No comments: