Basic Coding
Basic rules
Boolean values
false is signalized by nil
.
Anything other than nil
signalizes True.
For readability reasons, t
is also provided.
nil
Besides signalizing false values, nil
also represents the empty list ()
.
Variables
In EusLisp, global variables names are conventionally surrounded by *
, such as in *robot*
.
This notation allows clear understanding of each variable's scope, but is not obligatory.
Local variables can be introduced with let
. Such variables cannot be accessed from outside the let
statement.
(let (a)
(setq a 1))
a --> unbound variable error
Comments
Line comments start with ;
.
Block comments are surrounded by #|
and |#
.
Regarding line comments:
- ;
is indented at fixed depth, many times at column 40.
- ;;
is indented alongside code.
- ;;;
is not indented.
Lists
In EusLisp linear lists are used, and there is no array. Objects of different types can be stored in the same list.
Creating lists
Lists can be created with the function list
(setq *list* (list 0 1 2 3))
or with the '
notation.
(setq *list* '(0 1 2 3))
Refer to elements
Elements of a certain index can be accessed using elt
or nth
.
(elt *list* 0)
;; 0
(nth 0 *list*)
;; 0
The first element can be referred with car
.
(car *list*)
;; 0
cdr
gives the list of all but the first element.
(cdr *list*)
;; (1 2 3)
The last element can be referred with the following.
(car (last *list*))
;; 3
The length of the list is given by length
(length *list*)
;; 4
Editing lists
Lists can be joined with append
.
(setq *newlist* (append *list* (list 4 5 6)))
;; *newlist* is (0 1 2 3 4 5 6)
;; *list* remains unaltered
An element can be added with push
(destructive) or cons
(not destructive).
(push -1 *list*)
;; (-1 0 1 2 3)
pop
takes out the first element of the list destructively.
(pop *list*)
;; -1
;; *list* becomes (0 1 2 3)
Conditional clauses
when
when
is executed when the condition is non-nil
.
(when condition
(print "true"))
unless
unless
is the opposite of when
, being executed when the condition is nil
.
(unless condition
(print "false"))
cond
cond
is used for if-else-if like statements.
(setq *val* 0) ;; Try out with different values
(cond
((= *val* 0)
(print "val = 0"))
((= *val* 1)
(print "val = 1"))
(t
(print "default")))
In cond
, the first element of each s-expression is evaluated in order. If it is non-nil
the rest of the s-expression is executed and cond
exits; if it is nil
the next s-expression condition is evaluated.
In the above, the t
condition is executed when all of the above conditions do not apply (i.e. *val* is different from 0 and 1).
if
if
works like an if-else clause. If the condition is non-nil
the first s-expression is executed, else the second one is executed.
(if condition
(print "true")
(print "false"))
Because if
only deals with single s-expressions, progn
is used for evaluating multiple expressions in the same clause.
(if condition
(progn
(print "this")
(print " is ")
(print "true"))
(print "false"))
Iteration
dotimes
Similar to for
statement.
(dotimes (i 10)
(print i))
In the above, print
is executed for i
values from 0
to 9
.
dolist
Similar to foreach
.
(dolist (i (list 0 1 2 3))
(print i))
In the above, i
takes the value of each element in the list, from the start.
while
Loops while the condition is non-nil
.
(setq i 0)
(while (< i 10)
(print i)
(setq i (+ 1 i)))
The above is similar to the dotimes
example above.
(However, here i
is a global variable)
do-until-key
do-until-key
is a special iteration form. Instead of evaluating a certain condition, it is executed until the Enter
key is pressed.
(do-until-key
(print "press ENTER to stop"))
Other control clauses
return
return
is used to exit loops such as dotimes
, dolist
and while
.
(dotimes (i 10)
(when (= i 5) (return))
(print i))
return-from
return-from
is used to exit a block with the given name, such as ones signaled by a function or method.
Details will be given afterwards.
Functions and Classes
Functions
Functions are defined with defun
.
(defun plus (a b)
(+ a b))
And called as follows.
(plus 1 2)
The above is evaluates as 3
.
Functions return the last evaluated value.
Forced exit is done by return-from
.
(defun plus-minus (a b c)
(let (d e)
(setq d (- a b))
(when (< d 0)
(print "a < b, abort.")
(return-from plus-minus nil))
(setq e (- (+ a b) c))
e) ;; let returns e
)
In the above, try out the differences between
(plus-minus 1 2 3)
and
(plus-minus 2 1 3)
optional, key
It is possible to give default values for function arguments as follows.
(defun negate (a &optional (b 0))
(- b a))
In the above, it is possible to use both
(negate 10)
and
(negate 10 5)
Similarly, definition using key arguments is as follows.
(defun negate (a &key (b 0))
(- b a))
Which makes possible to use both
(negate 10)
and
(negate 10 :b 5)
Differently from &optional
, it is necessary to give key arguments by using :
followed by the variable name.
Classes
Classes and member functions can be defined as follows.
(defclass myclass
:super propertied-object
:slots (myname myage))
(defmethod myclass
(:init
(name age)
(setq myname name
myage age)
self)
(:myname
(&optional (newname nil))
(when newname (setq myname newname))
myname)
(:myage
(&optional (newage nil))
(when newage (setq myage newage))
(unless (= myage 17)
(print "something wrong.")
(return-from :myage 17))
17)
) ;; defmethod
In defclass
, :super
indicates the parent class, which will be inherited.
Here, the class propertied-object
is used.
Member variables are signalized by :slots
.
Member functions are defined with defmethod
, and have syntax similar to normal functions.
:init
is the constructor, which returns self
i.e. the instance itself.
Methods are defined with :
followed by the method name.
Class objects can be created with the following.
(setq *me* (instance myclass :init "John Smith" 30))
Methods are called by send
.
(send *me* :myname)
The above returns "John Smith"
.
(send *me* :myname "Alan Smithee")
The above replaces the member variable myname
with "Alan Smithee"
.
This way, it is possible to use the same method for set
and get
purposes.