The Slime 1.0 Manual
abstract
\tableofcontents
1 Lisp languages
Lisp is not one language but rather a family of programming languages. The family is devided by some characteristics. There are Lisp-1 and Lisp-2 dialects and there is a difference between a Lisp with lexical scoping as opposed to dynamic scoping. These differences will be explained in later sections.
Like most Lisps, Slime is dynamically typed. That means that like in statically typed Languages Slime has different data types, but they are associated not with variables but with the Lisp objects themselves. Variables can be assigend Lisp objects of any internal type.
The Lisp language family is known to be highly flexible and applicable in all areas by creating domain specific languages in Lisp itself through a powerful macro system. The central data structure in Lisp is the list. The reason why lisp is so powerful is because the program source code itself is represented as lists. The nested lists make up the syntax tree of the lisp program. It is therfore computationally easy to parse lisp programs as the source code itself is already structured in the form of the syntax tree; allowing for parsing in linear time.
The macro system in Slime works by recognizing macros at parse-time and running them, and replacing the macro call in the program code with the return value of the macro and then checking if further macros have to be expanded in the replaced code. Therefore the macros can be used to pre-compute values or rewrite expressions (creating syntactic sugar) or themselves define macros.
2 Lists
As mentioned in Lisp languages, the central data structure in all Lisps is the list. Lists are
implemented as singly linked lists, made up of pairs (historically called cons-cells), each pair
has two slots, the first and the rest (historically car and cdr). A linked lsit ist then
constructed by the convention that the first field of a pair points to the first element of the
list and the rest field points to the rest of the list. Following this description, the list is a
recursive data structure. For the end of the list a special value nil is used in the rest field.
A helpful way to visualize lists made up of pairs is using box diagrams. A simple box diagram can be
seen in 1. Each rectangle is divided in two. The left part represents the first
field, the right part represents the rest. The arrows point to the values in these fields.
The diagram in 1 shows a simple list containing the values 1, 2 and 3. The first pair
stores the number 1 its first field and the rest points to the rest of the list. The last pair
points to the special value nil in its rest to denote the end of the list.
However the rest of a pair needs not to be a pair or nil, it could also point to any other value.
By doing this the list is no longer "well formed" but rather "ill formed". Ill formed lsits can be
used as an optimization when using the list for storing data. In 2 an ill formed list
can be seen, that also contains the values 1, 2 and 3 but stores them using only two pairs instead
of 3.
2.1 representing lists in Lisp
In Slime and in most Lisps, lists are represented using round parenthesis where ( denotes the
start of the list and ) denotes the end. Eeach element inside these parenthesis separated by one
or more spaces will be interpreted as an element of that list. For example the list from
1 would be represented as (1 2 3). During parse time, the Lisp parser transforms
the parenthesised list into the pairs that are in the end stored in memory.
To also be able to represent ill formed lists in Lisp there is a special syntax using the . (dot
symbol). If the parser encounters a . inside of a list, it will treat the next element as the
rest. If there is no or more than one element after the . an parsing error will be thrown. Using
this syntax we can represent the ill formed list from 2 as (1 2 . 3). We can also
write well formed lists using the dot notation if we point the rest to another list. So the well
formed list from 1 can also be written as \[\texttt{(1 . (2 . (3)))}\]
2.2 representing function calls in Lisp
If we tried to enter the Lisp representation of the lists like (1 2 3) discussed in representing lists in Lisp directly into an Lisp interpreter we would get an error. That doesn't mean that the
explanation given in the section is wrong, it is in fact correct: the lisp parser will transform the
lisp syntax into the pairs in memory. The reason we would get an error is, that when reading Lisp
code, the Lisp interpreter first parses the code and then tries to evaluate it and return the result
back to the user.
In Lisp by default, a list corresponds to a function call. As mentioned in Lisp languages Lisp
represents lists and Lisp programms as lists. If a list is treated as a function call, the first
element will be treated as the function and the rest of the elements will be the arguments to that
function. If we would wnter (1 2 3) directly into the Lisp interpreter we would get an error
saying it cannot find the function 1.
If we would want to compute the sum of the numbers 5 and 3 we could do this by invoking the +
function with 5 and 3 as its arguments. (+ 5 3) will evaluate to 8. We can also nest functions
calls and use the return values as parameters to other functions: (+ (- 12 4) (/ 24 4)) will
evaluate to 14. The box diagramm showing the internal structure of that computation can be seen in
3.
3 Evaluation order
As a first step of evaluation of a regular function, all its arguments are getting evaluated, and
then the function is applied to the evaluated arguments. For example when evaluating the nested
expression in 1 the outermost function is the + function with three arguments: (*
3 4), (- 100 (+ 12 13 14 15)) and 2. So before the outhermost + gets invoked, the three
arguments are getting evaluated recursively.
(print (+ (* 3 4) (- 100 (+ 12 13 14 15)) 2))
evaluates to => 60
3.1 Special forms
The given evaluation rule – to evaluate all the arguments first and then allpying them to the
funciton – as described in Evaluation order is only valid for regular functions. There is a class
of functions that do not follow this evaluation rule called special forms. Special forms are
needed when you do not wish to evaluate all arguments. For example the built-in if function should
only evaluate the "then-expression" if the condition evaluates to a truthy value and not otherwise.
Consider the example in 2. The if expression only evaluates the then-expression. If
the if function would follow the evaluation order of regular functions, first all three arguments
(< 1 2), (print "I knew it!!\n") but also (print "Oh, it is not?!\n") could get evaluated and
so both messages would be printed. In the given if expression, the condition evaluates to a truthy
value and only I knew it!! will be printed.
(if (< 1 2) (print "I knew it!!\n") (print "Oh, it is not?!\n"))
evaluates to => I knew it!!
The programmer can also define their own special forms using special-lambda and macros, which will
be explained in Special lambdas and Macros.
4 Symbols and keywords
5 Truthyness
6 Lambdas
Slime allows for creating anonymous functions called lambdas. We did not talk about binding
variables, we will do this in Define, but we can still use lambdas now. Remember that Lisp
interpretes the first argument of a list in the source code as a function and the rest as the
arguments. The lambda special form evaluates to a regular function object that can then stand in
the first position of the function call list. The basic syntax for the lambda special form is:
\[\texttt{(lambda (arg1 arg2 ...) (body1) ...)}\] the first arguemnt to lambda is a list of the
arguments. All the following arguments will be the body of the lambda. They will be executed when
the lambda is invoked. The return value of a lambda is the value of the last evaluated expression in
the body.
Probably the simplest function to write as a lambda is the identity function. It takes one argument and returns it. The identity lambda and a few other simple examples of lambdas can be seen in 3.
(printf ((lambda (x) x) 1)) (printf ((lambda (x y) (+ x y)) 3 5)) (printf ((lambda (x y z) (list x y z)) 1 2 3))
evaluates to => 1 8 (1 2 3)
Additionally Slime lambdas have the possibility to take optional arguments in the form of keyword arguemnts as well as a rest argument which allows for accepting any number of arguments. Since these concepts are most useful when the function is actually bound to a variable, they will be introduced when we learned how to do that in Define.
6.1 Special lambdas
The lambda special form creates a function object that represents a regular function. So the basic
evaluation rules count: when the lambda is invoked all it's arguments are evaluated and then the
lambda is applied to the evaluated arguments. If this is not wanted in some rare cases, the
programmer also has the possibility to define a special form using special-lambda, which, when
invoked does not evaluare any argument. The programmer has to evaluate the arguments in the body
themselves using eval. The rest of the syntax between lambda and special-lambda are the same.
((lambda (x) (printf x)) (+ 1 2)) ((special-lambda (x) (printf x)) (+ 1 2)) ;; Special lambdas make it possible to write ;; code that inspects code ((special-lambda (expr) (printf "The function to be called is" (first expr) "and the result is" (eval expr))) (+ 1 2))
evaluates to => 3 (+ 1 2) The function to be called is + and the result is 3
7 Define
To assign a value to a symbol you can use the define built-in special form. The syntax for
define is: \[\texttt{(define symbol value)}\] and some usages can be seen in
5.
(define var1 1) (define var2 "Hello World") (define var3 (+ 1 2)) (printf var1 var2 var3)
evaluates to => 1 Hello World 3
7.1 Defining functions
In Lambdas we learned how to create function objects using the lambda built-in form. Using
define every Lisp Object can be assigned to a symbol making no exception for the function objects.
In 6 you can see what that would look like.
(define hypothenuse (lambda (a b) (** (+ (* a a) (* b b)) 0.5))) (printf (hypothenuse 3 4))
evaluates to => 5
Since defining functions is so common, there is a syntactic shorthand that does not require to write
out the whole lambda definition. In this case the first argument to the call to define is a
list. The frist element of the list is the name of the function to define and the other elemens are
the arguments to that function. An example can be seen in 7. Note that the
definition looks like a call to the function we are constructing, making it easier to see what a
call to that function will look like.
(define (hypothenuse a b) (** (+ (* a a) (* b b)) 0.5)) (printf (hypothenuse 3 4))
evaluates to => 5
7.2 Functions with keyword arguments
A sometimes more convenient way of passing arguments to a function is using keyword arguments. Using
keyword arguments a function call could look like this: \[\texttt{(function :arg1 value1 :arg2
value2)}\] here the function accepts two arguments named arg1 and arg2. The user of this
function can see more clearly excatly which argument will be assigned wich value. This notation also
allows for switching the argument order. The following function call is equivalent to the call
above. \[\texttt{(function :arg2 value2 :arg1 value1)}\].
For this to work however, the function must be defined to accept these keyword arguments. To do this
the special marker :keys has to be inserted into the argument list of a lambda or a function
define. All following arguments must be supplied as keyword arguments, unless they are also
supplied with a default value, in which case they do not need to be supplied. To attach a default
value to a keyword argument, insert :defaults-to <value> after the keyword argument name. An
example of all of this can be seen in 8. Important note: keyword arguments must be
defined and supplied after all the regular arguments.
(define (complex required1 required2 :keys key1 key2 :defaults-to 3 key3) (* (+ required1 required2) key1 key2 key3)) (printf (complex 1 2 :key1 2 :key2 2 :key3 3)) (printf (complex 1 2 :key1 2 :key3 3)) (printf (complex 1 2 :key3 3 :key1 2))
evaluates to => 36 54 54
7.3 Functions with rest arguments
If the programmer wants to create a function that can accept any number of arguments, they can use
the rest argument. It is defined after the special marker :rest and after the rest argument, no
other arguments can be defined. In the execution of the fuction, the rest arguent will be assigned
to a list containing all the supplied values. The rest argument can be used in conjunction with the
other argument types, regular arguments and keyword arguments.
(define (execute-operation operation :keys do-logging :defaults-to () :rest values) (define result (apply operation values)) (when do-logging (printf "Executing operation" operation "agains the values" values "yielded:" result)) result) (printf (execute-operation '+ 1 2 3)) (printf (execute-operation '* :do-logging t 10 11))
evaluates to => 6 Executing operation * agains the values (10 11) yielded: 110 110
8 Environments
9 Macros
Built-in functions
\hrule
=
- defined in
src/./built_ins.cpp:158:0- type
:cfunction- docu
Takes 0 or more arguments and returns
tif all arguments are equal and()otherwise.
\hrule
>
- defined in
src/./built_ins.cpp:175:0- type
:cfunction- docu
TODO
\hrule
>=
- defined in
src/./built_ins.cpp:193:0- type
:cfunction- docu
TODO
\hrule
<
- defined in
src/./built_ins.cpp:211:0- type
:cfunction- docu
TODO
\hrule
<=
- defined in
src/./built_ins.cpp:231:0- type
:cfunction- docu
TODO
\hrule
+
- defined in
src/./built_ins.cpp:249:0- type
:cfunction- docu
TODO
\hrule
-
- defined in
src/./built_ins.cpp:262:0- type
:cfunction- docu
TODO
\hrule
*
- defined in
src/./built_ins.cpp:285:0- type
:cfunction- docu
TODO
\hrule
/
- defined in
src/./built_ins.cpp:306:0- type
:cfunction- docu
TODO
\hrule
**
- defined in
src/./built_ins.cpp:327:0- type
:cfunction- docu
TODO
\hrule
%
- defined in
src/./built_ins.cpp:343:0- type
:cfunction- docu
TODO
\hrule
assert
- defined in
src/./built_ins.cpp:359:0- type
:cfunction- docu
TODO
\hrule
define
- defined in
src/./built_ins.cpp:371:0- type
:cfunction- docu
TODO
\hrule
mutate
- defined in
src/./built_ins.cpp:433:0- type
:cfunction- docu
TODO
\hrule
if
- defined in
src/./built_ins.cpp:458:0- type
:cfunction- docu
TODO
\hrule
quote
- defined in
src/./built_ins.cpp:480:0- type
:cfunction- docu
TODO
\hrule
quasiquote
- defined in
src/./built_ins.cpp:485:0- type
:cfunction- docu
TODO
\hrule
and
- defined in
src/./built_ins.cpp:583:0- type
:cfunction- docu
TODO
\hrule
or
- defined in
src/./built_ins.cpp:594:0- type
:cfunction- docu
TODO
\hrule
not
- defined in
src/./built_ins.cpp:605:0- type
:cfunction- docu
TODO
\hrule
while
- defined in
src/./built_ins.cpp:615:0- type
:cfunction- docu
TODO
\hrule
lambda
- defined in
src/./built_ins.cpp:693:0- type
:cfunction- docu
TODO
\hrule
special-lambda
- defined in
src/./built_ins.cpp:705:0- type
:cfunction- docu
TODO
\hrule
eval
- defined in
src/./built_ins.cpp:713:0- type
:cfunction- docu
TODO
\hrule
begin
- defined in
src/./built_ins.cpp:725:0- type
:cfunction- docu
TODO
\hrule
list
- defined in
src/./built_ins.cpp:741:0- type
:cfunction- docu
TODO
\hrule
pair
- defined in
src/./built_ins.cpp:745:0- type
:cfunction- docu
TODO
\hrule
first
- defined in
src/./built_ins.cpp:755:0- type
:cfunction- docu
TODO
\hrule
rest
- defined in
src/./built_ins.cpp:766:0- type
:cfunction- docu
TODO
\hrule
set-type
- defined in
src/./built_ins.cpp:777:0- type
:cfunction- docu
TODO
\hrule
delete-type
- defined in
src/./built_ins.cpp:789:0- type
:cfunction- docu
TODO
\hrule
type
- defined in
src/./built_ins.cpp:796:0- type
:cfunction- docu
TODO
\hrule
info
- defined in
src/./built_ins.cpp:828:0- type
:cfunction- docu
TODO
\hrule
show
- defined in
src/./built_ins.cpp:910:0- type
:cfunction- docu
TODO
\hrule
addr-of
- defined in
src/./built_ins.cpp:922:0- type
:cfunction- docu
TODO
\hrule
generate-docs
- defined in
src/./built_ins.cpp:928:0- type
:cfunction- docu
TODO
\hrule
print
- defined in
src/./built_ins.cpp:937:0- type
:cfunction- docu
TODO
\hrule
read
- defined in
src/./built_ins.cpp:945:0- type
:cfunction- docu
TODO
\hrule
exit
- defined in
src/./built_ins.cpp:962:0- type
:cfunction- docu
TODO
\hrule
break
- defined in
src/./built_ins.cpp:973:0- type
:cfunction- docu
TODO
\hrule
memstat
- defined in
src/./built_ins.cpp:978:0- type
:cfunction- docu
TODO
\hrule
try
- defined in
src/./built_ins.cpp:982:0- type
:cfunction- docu
TODO
\hrule
load
- defined in
src/./built_ins.cpp:997:0- type
:cfunction- docu
TODO
\hrule
import
- defined in
src/./built_ins.cpp:1008:0- type
:cfunction- docu
TODO
\hrule
copy
- defined in
src/./built_ins.cpp:1019:0- type
:cfunction- docu
TODO
\hrule
error
- defined in
src/./built_ins.cpp:1027:0- type
:cfunction- docu
TODO
\hrule
symbol->keyword
- defined in
src/./built_ins.cpp:1034:0- type
:cfunction- docu
TODO
\hrule
string->symbol
- defined in
src/./built_ins.cpp:1043:0- type
:cfunction- docu
TODO
\hrule
symbol->string
- defined in
src/./built_ins.cpp:1055:0- type
:cfunction- docu
TODO
\hrule
concat-strings
- defined in
src/./built_ins.cpp:1064:0- type
:cfunction- docu
TODO
\hrule
pe
- defined in
pre.slime:2:40- type
:macro- arguments
- :
- postitional
expr
- docu
- none
\hrule
when
- defined in
pre.slime:8:37- type
:macro- arguments
- :
- postitional
condition:- rest
body
- docu
Doc String for `when'
\hrule
unless
- defined in
pre.slime:13:41- type
:macro- arguments
- :
- postitional
condition:- rest
body
- docu
- none
\hrule
n-times
- defined in
pre.slime:20:35- type
:macro- arguments
- :
- postitional
times,action
- docu
Executes action times times.
\hrule
let
- defined in
pre.slime:37:64- type
:macro- arguments
- :
- postitional
bindings:- rest
body
- docu
- none
\hrule
cond
- defined in
pre.slime:51:19- type
:macro- arguments
- :
- rest
clauses
- docu
- none
\hrule
define-special
- defined in
pre.slime:54:81- type
:macro- arguments
- :
- postitional
name-and-args:- rest
body
- docu
- none
\hrule
construct-list
- defined in
pre.slime:94:14- type
:macro- arguments
- :
- rest
body
- docu
(construct-list i <- '(1 2 3 4 5) yield (* i i))
(construct-list i <- '(1 2 3 4) j <- '(A B) yield (pair i j))
(construct-list i <- '(1 2 3 4 5 6 7 8) when (evenp i) yield i)
\hrule
apply
- defined in
pre.slime:99:28- type
:macro- arguments
- :
- postitional
fun,seq
- docu
Applies the funciton to the sequence, as in calls the function with ithe sequence as arguemens.
\hrule
define-package
- defined in
pre.slime:113:24- type
:macro- arguments
- :
- postitional
name:- rest
body
- docu
- none
\hrule
nil?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is
nil.
\hrule
number?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a number.
\hrule
symbol?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a symbol.
\hrule
keyword?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a keyword.
\hrule
pair?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a pair.
\hrule
string?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a string.
\hrule
lambda?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a function.
\hrule
macro?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a macro.
\hrule
special-lambda?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a special-lambda.
\hrule
built-in-function?
- type
:lambda- arguments
- :
- postitional
x
- docu
Checks if the argument is a built-in function.
\hrule
callable?
- type
:lambda- arguments
- :
- postitional
x
- docu
- none
\hrule
end
- type
:lambda- arguments
- :
- postitional
seq
- docu
Returns the last pair in the sqeuence.
\hrule
last
- type
:lambda- arguments
- :
- postitional
seq
- docu
Returns the (first) of the last (pair) of the given sequence.
\hrule
extend
- type
:lambda- arguments
- :
- postitional
seq,elem
- docu
Extends a list with the given element, by putting it in the (rest) of the last element of the sequence.
\hrule
extend2
- type
:lambda- arguments
- :
- postitional
seq,elem
- docu
Extends a list with the given element, by putting it in the (rest) of the last element of the sequence.
\hrule
append
- type
:lambda- arguments
- :
- postitional
seq,elem
- docu
Appends an element to a sequence, by extendeing the list with (pair elem nil).
\hrule
length
- type
:lambda- arguments
- :
- postitional
seq
- docu
Returns the length of the given sequence.
\hrule
increment
- type
:lambda- arguments
- :
- postitional
val
- docu
Adds one to the argument.
\hrule
decrement
- type
:lambda- arguments
- :
- postitional
val
- docu
Subtracts one from the argument.
\hrule
range
- type
:lambda- arguments
- :
- keyword
from(0),to
- docu
Returns a sequence of numbers starting with the number defined by the key
fromand ends with the number defined into.
\hrule
range-while
- type
:lambda- arguments
- :
- keyword
from(0),to
- docu
Returns a sequence of numbers starting with the number defined by the key 'from' and ends with the number defined in 'to'.
\hrule
map
- type
:lambda- arguments
- :
- postitional
fun,seq
- docu
Takes a function and a sequence as arguments and returns a new sequence which contains the results of using the first sequences elemens as argument to that function.
\hrule
reduce
- type
:lambda- arguments
- :
- postitional
fun,seq
- docu
Takes a function and a sequence as arguments and applies the function to the argument sequence. This only works correctly if the given function accepts a variable amount of parameters. If your funciton is limited to two arguments, use
reduce-binaryinstead.
\hrule
reduce-binary
- type
:lambda- arguments
- :
- postitional
fun,seq
- docu
Takes a function and a sequence as arguments and applies the function to the argument sequence. reduce-binary applies the arguments `pair-wise' which means it works with binary functions as compared to `reduce'.
\hrule
filter
- type
:lambda- arguments
- :
- postitional
fun,seq
- docu
Takes a function and a sequence as arguments and applies the function to every value in the sequence. If the result of that funciton application returns a truthy value, the original value is added to a list, which in the end is returned.
\hrule
zip
- type
:lambda- arguments
- :
- postitional
l1,l2
- docu
- none
\hrule
unzip
- type
:lambda- arguments
- :
- postitional
lists
- docu
- none
\hrule
enumerate
- type
:lambda- arguments
- :
- postitional
seq
- docu
- none
\hrule
printf
- type
:lambda- arguments
- :
- keyword
sep(" "),end("\n"):- rest
args
- docu
A wrapper for the built-in
printthat accepts a variable number of arguments and also provides keywords for specifying the printed separators (sep) between the arguments and what should be printed after the las argument (end).
\hrule
define-class
- defined in
oo.slime:22:22- type
:macro- arguments
- :
- postitional
name-and-members:- rest
body
- docu
Macro for creating simple classes.
\hrule
->
- defined in
oo.slime:25:24- type
:macro- arguments
- :
- postitional
obj,meth:- rest
args
- docu
- none
\hrule
math->
- type
:package- arguments
- :
- rest
args
- docu
- none
\hrule
math-> pi
- defined in
math.slime:5:4- type
:number- value
3.141593- docu
Tha famous circle constant.
\hrule
math-> abs
- defined in
math.slime:9:4- type
:lambda- arguments
- :
- postitional
x
- docu
Accepts one argument and returns the absoulte value of it
\hrule
math-> sqrt
- defined in
math.slime:13:4- type
:lambda- arguments
- :
- postitional
x
- docu
Accepts one argument and returns the square root of it
\hrule
math-> make-vector3
- defined in
pre.slime:37:63- type
:constructor- arguments
- :
- postitional
x,y,z
- docu
This is the handle to an object of the class vector3
\hrule
math-> make-vector3 define-class
- defined in
oo.slime:22:22- type
:macro- arguments
- :
- postitional
name-and-members:- rest
body
- docu
Macro for creating simple classes.
\hrule
math-> make-vector3 ->
- defined in
oo.slime:25:24- type
:macro- arguments
- :
- postitional
obj,meth:- rest
args
- docu
- none