This is an old revision of the document!


Lisp Crash Course

Todo: proper formatting and explanation text.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DATATYPES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
CL-USER> 123
123
CL-USER> "bla"
"bla"
CL-USER> *
"bla"
CL-USER> #\c
#\c
 
CL-USER> #b111
7
 
CL-USER> 1/5
1/5
CL-USER> 3/6
1/2
CL-USER> (* * **)
1/10
 
CL-USER> 1e-5
1.e-5
CL-USER> (+ 1 1e-5)
1.00001
CL-USER> 1.0
1.0
CL-USER> 1e-5
1.e-5
CL-USER> (+ 1 *)
1.00001
CL-USER> (1+ **)
1.00001
CL-USER> 1d0
1.0d0
CL-USER> 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
CL-USER> (* * 333333333333333333333333333333333333333333333)
740740740740740740740740740740740740740740739999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999925925925925925925925925925925925925925925926
 
CL-USER> 'cat
CAT
CL-USER> (describe 'cat)
COMMON-LISP-USER::CAT
  [symbol]
; No value
 
 
CL-USER> (+ 1 2 3)
6
CL-USER> (max 3 6)
6
CL-USER> (describe 'max)
COMMON-LISP:MAX
  [symbol]
 
MAX names a compiled function:
  Lambda-list: (NUMBER &REST MORE-NUMBERS)
  Declared type: (FUNCTION (REAL &REST REAL) (VALUES REAL &OPTIONAL))
  Derived type: (FUNCTION (T &REST T) (VALUES NUMBER &OPTIONAL))
  Documentation:
    Return the greatest of its arguments; among EQUALP greatest, return
    the first.
  Known attributes: foldable, flushable, unsafely-flushable, movable, explicit-check
  Source file: SYS:SRC;CODE;NUMBERS.LISP
; No value
CL-USER> (list 'max 3 6)
(MAX 3 6)  ;;;;;;;;;;;;;;;;  (inspect)
CL-USER> *
(MAX 3 6)
CL-USER> (first *)
MAX
CL-USER> (second **)
3
CL-USER> (eval ***)
6
CL-USER> '(max 3 6)
(MAX 3 6)
CL-USER> (second *)
3
 
 
CL-USER> '()
NIL
CL-USER> ()
NIL
CL-USER> (describe ())
COMMON-LISP:NIL
  [null]
 
NIL names a constant variable:
  Value: NIL
 
NIL names a primitive type-specifier:
  (undocumented)
; No value
 
 
 
CL-USER> (describe 't)
COMMON-LISP:T
  [symbol]
 
T names a constant variable:
  Value: T
 
T names the built-in-class #<BUILT-IN-CLASS T>:
  Class precedence-list: T
  Direct subclasses: SEQUENCE, ARRAY, SIMD-PACK, NUMBER,
                     SB-KERNEL::RANDOM-CLASS, SB-KERNEL:FDEFN,
                     SB-KERNEL:LRA, SB-KERNEL:CODE-COMPONENT,
                     WEAK-POINTER, SYSTEM-AREA-POINTER, SYMBOL,
                     CHARACTER, SB-PCL::SLOT-OBJECT, STREAM, FUNCTION
  No direct slots.
 
T names a primitive type-specifier:
  (undocumented)
; No value
CL-USER> (describe 'nil)
COMMON-LISP:NIL
  [null]
 
NIL names a constant variable:
  Value: NIL
 
NIL names a primitive type-specifier:
  (undocumented)
; No value
CL-USER> (describe t)
COMMON-LISP:T
  [symbol]
 
T names a constant variable:
  Value: T
 
T names the built-in-class #<BUILT-IN-CLASS T>:
  Class precedence-list: T
  Direct subclasses: SEQUENCE, ARRAY, SIMD-PACK, NUMBER,
                     SB-KERNEL::RANDOM-CLASS, SB-KERNEL:FDEFN,
                     SB-KERNEL:LRA, SB-KERNEL:CODE-COMPONENT,
                     WEAK-POINTER, SYSTEM-AREA-POINTER, SYMBOL,
                     CHARACTER, SB-PCL::SLOT-OBJECT, STREAM, FUNCTION
  No direct slots.
 
T names a primitive type-specifier:
  (undocumented)
; No value
 
 
CL-USER> '(if t
           (print "true")
           (print "false"))
(IF T
    (PRINT "true")
    (PRINT "false"))
CL-USER> (eval *)
 
"true" 
"true"
 
;;;;;;;;;;;;; jede eingabe: erstmal datenstruktur, dann kompiliert, dann ausgefuehrt
 
CL-USER> (IF T     ;;;;;;;;;;;;; left click
    (PRINT "true")
    (PRINT "false"))
"true" 
"true"
CL-USER> (MaX 2 3 4)
4
CL-USER> (when 0                  ;;;;;;;;;;;;; compiler?
           (print "hoho"))
 
"hoho" 
"hoho"
CL-USER> #(5 4 3 2)
#(5 4 3 2)
CL-USER> (describe *)
#(5 4 3 2)
  [simple-vector]
 
Element-type: T
Length: 4
; No value
 
 
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FUNCTIONS ;;;;;;;;;;;;;;;;;;;
 
 
CL-USER> (defun say-hello ()
           (print "helloooo"))
SAY-HELLO
CL-USER> (say-hello)
 
"helloooo" 
"helloooo"
CL-USER> (describe 'say-hello)
COMMON-LISP-USER::SAY-HELLO
  [symbol]
 
SAY-HELLO names a compiled function:
  Lambda-list: ()
  Derived type: (FUNCTION NIL
                 (VALUES (SIMPLE-ARRAY CHARACTER (8)) &OPTIONAL))
  Source form:
    (SB-INT:NAMED-LAMBDA SAY-HELLO
        NIL
      (BLOCK SAY-HELLO (PRINT "helloooo")))
; No value
;;;;;;;;;;;;;;;;;;;;;;; inspect compiled code
 
 
CL-USER> (sb-ext:gc :full t)
NIL
 
 
CL-USER> (list 'defun 'return-a '(a) 'a)
(DEFUN RETURN-A (A) A)
CL-USER> (eval *)
RETURN-A
CL-USER> (return-a 5)
5
 
CL-USER> (defun if ())
; in: DEFUN IF
;     (SB-INT:NAMED-LAMBDA IF
;         NIL
;       (BLOCK IF))
; 
; caught ERROR:
;   Special form is an illegal function name: IF
; 
; compilation unit aborted
;   caught 1 fatal ERROR condition
;   caught 1 ERROR condition
; Evaluation aborted on #<SB-INT:SIMPLE-PROGRAM-ERROR "Special form is an illegal function name: ~S" {100C93BE63}>.
CL-USER> (defun when ())
; 
; compilation unit aborted
;   caught 1 fatal ERROR condition
; Evaluation aborted on #<SYMBOL-PACKAGE-LOCKED-ERROR "proclaiming ~S as a function" {100CB00B03}>.
 
;;;;;;;;;;;;;;;;;;;;;; sleep loop with compiled function and .fasl
 
 
CL-USER> (defvar *db* '((Anna 1987) (Bob 1899) (Charlie 1980)))
*DB*
CL-USER> (defun name-and-year (id)
           (values (first (nth (- id 1) *db*))
                   (second (nth (- id 1) *db*))))
NAME-AND-YEAR
CL-USER> (name-and-year 2)
BOB
1899
CL-USER> (multiple-value-bind (name year)
             (name-and-year 3)
           (format t "~a was born in ~a.~%" name year))
CHARLIE was born in 1980.
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SYMBOLS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
CL-USER> (setf max 234)   ;;;;;;;;;;;;;;;;; max = 234
; in: SETF MAX
;     (SETF MAX 234)
; ==>
;   (SETQ MAX 234)
; 
; caught WARNING:
;   undefined variable: MAX
; 
; compilation unit finished
;   Undefined variable:
;     MAX
;   caught 1 WARNING condition
234
CL-USER> max          ;;;;;;; <- variable, da ohne klammer und apostroph
234
CL-USER> ;;;;;;;;;;;defvar...
 
CL-USER> 'max
MAX      ;;;;;;;;; inspect
 
 
((((((((((((((( property lists, only if asked
CL-USER> (setf (get 'max 'my-property) 3)
3
CL-USER> (setf (get 'max 'my-other-property) 5)
5
         ;;;; inspect
 
CL-USER> (setf my-var '(my-prop 3 my-other-prop 5))
CL-USER> (getf my-var 'my-prop)
3
CL-USER> 'my-var
MY-VAR       ;;;;;;;;; inspect
)))))))))))))))
 
CL-USER> '%awesome?or-not->symbol_1234фыва^2
%AWESOME?OR-NOT->SYMBOL_1234ФЫВА^2
CL-USER> (setf %awesome?or-not->symbol_1234фыва^2 234)
 
; in: SETF %AWESOME?OR-NOT->SYMBOL_1234ФЫВА^2
;     (SETF %AWESOME?OR-NOT->SYMBOL_1234ФЫВА^2 234)
; ==>
;   (SETQ %AWESOME?OR-NOT->SYMBOL_1234ФЫВА^2 234)
; 
; caught WARNING:
;   undefined variable: %AWESOME?OR-NOT->SYMBOL_1234ФЫВА^2
; 
; compilation unit finished
;   Undefined variable:
;     %AWESOME?OR-NOT->SYMBOL_1234ФЫВА^2
;   caught 1 WARNING condition
234
CL-USER> %awesome?or-not->symbol_1234фыва^2
234
;;;;;;;;;;; inspect symbol
 
CL-USER> (intern "YOYO")
YOYO
NIL
CL-USER> (dotimes (i 3)
           (set (intern (format nil "CAT-~a" i)) i))
NIL
CL-USER> cat-2
2
CL-USER> (intern "hello
world")
|hello
world|
NIL
 
;;;;;;;;;;;;;;;;;;;;;;;;; FUNCTIONS AS FIRST CLASS CITIZENS ;;;;;;;;;;;;;;;;;;;;;;;
 
CL-USER> (describe '>)
COMMON-LISP:>
  [symbol]
 
> names a compiled function:
  Lambda-list: (NUMBER &REST MORE-NUMBERS)
  Declared type: (FUNCTION (REAL &REST REAL)
                  (VALUES (MEMBER T NIL) &OPTIONAL))
  Derived type: (FUNCTION (T &REST T) (VALUES (MEMBER NIL T) &OPTIONAL))
  Documentation:
    Return T if its arguments are in strictly decreasing order, NIL otherwise.
  Known attributes: foldable, flushable, unsafely-flushable, movable, predicate, explicit-check
  Source file: SYS:SRC;CODE;NUMBERS.LISP
; No value
CL-USER> (describe #'>)
#<FUNCTION >>
  [compiled function]
 
Lambda-list: (NUMBER &REST MORE-NUMBERS)
Declared type: (FUNCTION (REAL &REST REAL)
                (VALUES (MEMBER T NIL) &OPTIONAL))
Derived type: (FUNCTION (T &REST T) (VALUES (MEMBER NIL T) &OPTIONAL))
Documentation:
  Return T if its arguments are in strictly decreasing order, NIL otherwise.
Known attributes: foldable, flushable, unsafely-flushable, movable, predicate, explicit-check
Source file: SYS:SRC;CODE;NUMBERS.LISP
; No value
 
CL-USER> (sort '(28672 3766 3 7 111111 8 5  -235) #'>)
(111111 28672 3766 8 7 5 3 -235)
CL-USER> (sort '(28672 3766 3 7 111111 8 5  -235) #'<)
(-235 3 5 7 8 3766 28672 111111)
CL-USER> (defun fancy-sort (x y)
           (> (abs x) (abs y)))
FANCY-SORT
CL-USER> (sort '(28672 3766 3 7 111111 8 5  -235) #'fancy-sort)
(111111 28672 3766 -235 8 7 5 3)
CL-USER> (sort '(28672 3766 3 7 111111 8 5  -235)
               (lambda (x y)
                 (> (abs x) (abs y))))
(111111 28672 3766 -235 8 7 5 3)
 
 
CL-USER> (setf my-list '(10 -25 47 20 -46 0))
 
; in: SETF MY-LIST
;     (SETF MY-LIST '(10 -25 47 20 -46 0))
; ==>
;   (SETQ MY-LIST '(10 -25 47 20 -46 0))
; 
; caught WARNING:
;   undefined variable: MY-LIST
; 
; compilation unit finished
;   Undefined variable:
;     MY-LIST
;   caught 1 WARNING condition
(10 -25 47 20 -46 0)
CL-USER> (mapcar #'abs my-list)
(10 25 47 20 46 0)
CL-USER> (mapcar (lambda (x) (* x -1)) my-list)
(-10 25 -47 -20 46 0)
CL-USER> (+ '(1 2 3) '(2 3 4))
; Evaluation aborted on #<TYPE-ERROR expected-type: NUMBER datum: (1 2 3)>.
CL-USER> (mapcar #'+ '(1 2 3) '(2 3 4))
(3 5 7)
CL-USER> (expt 2 3)
8
CL-USER> (reduce #'expt '(2 3 2))
64
 
 
CL-USER> (defun x^10 (x)
           (expt x 10))
 
X^10
CL-USER> (dolist (elem '(2 3 4))
           (format t "~a^10 = ~a~%"
                   elem (x^10 elem)))
2^10 = 1024
3^10 = 59049
4^10 = 1048576
NIL
CL-USER> (asdf:load-system :alexandria)
T
CL-USER> (dolist (elem '(2 3 4))
           (format t "~a^10 = ~a~%"
                   elem (funcall (alexandria:curry #'expt 10) elem)))
2^10 = 100
3^10 = 1000
4^10 = 10000
NIL
CL-USER> (dolist (elem '(2 3 4))
           (format t "~a^10 = ~a~%"
                   elem (funcall (alexandria:rcurry #'expt 10) elem)))
2^10 = 1024
3^10 = 59049
4^10 = 1048576
NIL
 
 
CL-USER> my-list
(10 -25 47 20 -46 0)
CL-USER> (first *)
10
CL-USER> (rest **)
(-25 47 20 -46 0)
CL-USER> (labels ((invert (the-list &optional acc)
                    (if (null the-list)
                        acc
                        (invert (rest the-list) (cons (first the-list) acc)))))
           (invert my-list))
 
;     (INVERT MY-LIST)
; 
; caught WARNING:
;   undefined variable: MY-LIST
; 
; compilation unit finished
;   Undefined variable:
;     MY-LIST
;   caught 1 WARNING condition
(0 -46 20 47 -25 10)
 
 
CL-USER> (let ((counter 0))
           (defun count-cats ()
             (incf counter)))
COUNT-CATS
CL-USER> (count-cats)
1
CL-USER> (count-cats)
2
CL-USER> (count-cats)
3
;;;;;;;;;; inspect
CL-USER> counter
; Evaluation aborted on #<UNBOUND-VARIABLE COUNTER {10097B09E3}>.
 
 
 
CL-USER> (defclass shape ()
           ((color :accessor get-shape-color
                   :initarg :set-color)
            (center :accessor shape-center
                    :initarg :center
                    :initform '(0 . 0))))
#<STANDARD-CLASS SHAPE>
CL-USER> (defvar *red-shape* (make-instance 'shape :set-color 'red))
*RED-SHAPE*
CL-USER> *red-shape*
#<SHAPE {100A0E5703}>
CL-USER> (describe *)
#<SHAPE {100A0E5703}>
  [standard-object]
 
Slots with :INSTANCE allocation:
  COLOR   = RED
  CENTER  = (0 . 0)
; No value
CL-USER> (defclass circle (shape)
           ((radius :initarg :radius)))
#<STANDARD-CLASS CIRCLE>
CL-USER> (defvar *circle*
           (make-instance 'circle :set-color 'green :radius 10))
*CIRCLE*
CL-USER> *circle*
#<CIRCLE {100A194D93}>   ;;;;;;;;;;; inspect
CL-USER> (defgeneric area (x)
           (:documentation "Calculates area of object of type SHAPE."))
#<STANDARD-GENERIC-FUNCTION AREA (0)>
CL-USER> (area 1)
; Evaluation aborted on #<SIMPLE-ERROR "~@<There is no applicable method for the generic function ~2I~_~S~
;          ~I~_when called with arguments ~2I~_~S.~:>" {100A36A1D3}>.
CL-USER> (defmethod area (x)
           (error "AREA is only applicable to SHAPE instances"))
#<STANDARD-METHOD AREA (T) {100A550473}>
CL-USER> (area 1)
; Evaluation aborted on #<SIMPLE-ERROR "AREA is only applicable to SHAPE instances" {100A675C93}>.
CL-USER> (defmethod area ((obj shape))
           (error "We need more information about OBJ to know its area"))
#<STANDARD-METHOD AREA (SHAPE) {100A84F883}>
CL-USER> (area *red-shape*)
; Evaluation aborted on #<SIMPLE-ERROR "We need more information about OBJ to know its area" {100A855053}>.
CL-USER> (defmethod area ((obj string))
           (print obj))
#<STANDARD-METHOD AREA (STRING) {100AA4A533}>
CL-USER> (area "bla")
 
"bla" 
"bla"
CL-USER> (defmethod area ((obj circle))
           (* pi (expt (slot-value obj 'radius) 2)))
#<STANDARD-METHOD AREA (CIRCLE) {100AB2E5D3}>
CL-USER> (area *circle*)
314.1592653589793d0
CL-USER> (defmethod area :before (obj)
           (print "before area"))
#<STANDARD-METHOD AREA :BEFORE (T) {100AB92773}>
CL-USER> (area *circle*)
 
"before area" 
314.1592653589793d0
CL-USER> (defmethod area :around ((obj shape))
           (format t "hallo~%"))
#<STANDARD-METHOD AREA :AROUND (SHAPE) {100AD15683}>
CL-USER> (area *red-shape*)
hallo
NIL
CL-USER> (defmethod area :around ((obj shape))
           (format t "hallo~%")
           (call-next-method))
STYLE-WARNING: redefining AREA :AROUND (#<STANDARD-CLASS SHAPE>) in DEFMETHOD
#<STANDARD-METHOD AREA :AROUND (SHAPE) {100AE65183}>
CL-USER> (area *red-shape*)
hallo
 
"before area" ; Evaluation aborted on #<SIMPLE-ERROR "We need more information about OBJ to know its area" {100AE6C783}>.
CL-USER> (defmethod :area :around ((obj circle))
           (* (call-next-method) 2))
 
STYLE-WARNING: Implicitly creating new generic function :AREA.
#<STANDARD-METHOD :AREA :AROUND (CIRCLE) {100B122543}>
CL-USER> (area *circle*)
hallo
 
"before area" 
314.1592653589793d0
CL-USER> (defgeneric awesome-function (x)
           (:method-combination +))
#<STANDARD-GENERIC-FUNCTION AWESOME-FUNCTION (0)>
CL-USER> (defmethod awesome-function + ((x number))
           x)
#<STANDARD-METHOD AWESOME-FUNCTION + (NUMBER) {100B20C413}>
CL-USER> (awesome-function 2)
2
CL-USER> (typep 3 'number)
T
CL-USER> (typep 3 'integer)
T
CL-USER> (defmethod awesome-function + ((x integer))
           x)
#<STANDARD-METHOD AWESOME-FUNCTION + (INTEGER) {100B400293}>
CL-USER> (awesome-function 2)
4
CL-USER> (defgeneric list-function (x)
           (:method-combination list))
#<STANDARD-GENERIC-FUNCTION LIST-FUNCTION (0)>
CL-USER>  (defmethod list-function list ((x number))
           x)
#<STANDARD-METHOD LIST-FUNCTION LIST (NUMBER) {100B66B623}>
CL-USER> (defmethod list-function list ((x integer))
           x)
#<STANDARD-METHOD LIST-FUNCTION LIST (INTEGER) {100B6CBC43}>
CL-USER> (list-function 123)
(123 123)
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MACROS ;;;;;;;;;;;;;;;;;;;;;;;;
 
CL-USER> (defmacro square (&whole form arg)
           (if (atom arg)
               `(expt ,arg 2)
               (case (car arg)
                 (square (if (= (length arg) 2)
                             `(expt ,(nth 1 arg) 4)
                             form))
                 (expt (if (= (length arg) 3)
                           (if (numberp (nth 2 arg))
                               `(expt ,(nth 1 arg) ,(* 2 (nth 2 arg)))
                               `(expt ,(nth 1 arg) (* 2 ,(nth 2 arg))))
                           form))
                 (otherwise `(expt ,arg 2)))))
SQUARE
CL-USER> (square 3)
9
CL-USER> (square -3)
9
CL-USER> (square (square 2))
16
CL-USER> (square (expt 2 5))
1024

Hello world function

As any other language we start with hello-world function :

CL-USER> (defun hello-world ()
	(format t “hello world”)

We will talk about defun more later. But now we consider some basic mathematical operator in lisp. You can run them in your repl and track the results :

CL-USER>(+  1  1e-5)
CL-USER>(+ 1 2 3)
CL-USER>(* * 2)

Defun

By using defun we can define new function with different arguments. Any symbol can be used as a function name and it is not mandatory like most of the other languages to only use alphabetic characters for the function name.

CL-USER>(defun function-name (parameters*)
	(body-forms*))

When we want to call the function, we should pass the arguments that we define in the definition of the function. If the function takes no arguments, the list is empty, written as (). Anyway you should consider that we can handle different type of parameters, constant number of parameters, optional parameters and multiple parameters.

CL-USER>(defun function-name (arg1 arg2 arg3 arg4)
	(list arg1 arg2 arg3 arg4))

Optional arguments

Sometime a function might have some parameters which only consider by some of the callers of the function. perhaps because there's a reasonable default value. If in any cases some arguments are optional, in this situation after the names of any required parameters, place the symbol &optional followed by the names of the optional parameters.

CL-USER>(defun function-name-optional 
	(arg1 arg2 &optional arg3 arg4))

Please find the example below as a function that can take some optional arguments.

CL-USER>(defun optional-function (a b &optional c d) (list a b c d))

After the function is called arguments are assigned to the required parameters. Since then if any other parameters are left, their values are given to the optional parameters. If the arguments run out before the optional parameters do, the remaining optional parameters are bound to the value NIL.

CL-USER>(optional-function 1 2 3)
(1 2 3 NIL)

Of course most of the time it is not acceptable to have parameter that is NIL so it is better to assign a default value to the optional parameter.

CL-USER>(defun optional-function (a &optional (b 10)) (list a b))
 
CL-USER>(optional-function 1 2)
(1 2)
 
CL-USER>(optional-function 1)
(1 10)

Example : define a function that can take 3 numbers and get the average of them

CL-USER>(defun get-avg (num-1 num-2 num-3)
	(/ (+ num-1 num-2 num-3) 3))
 
CL-USER>(format t “avg 10 & 20 & 30 = -a ~%(get-avg 10 20 30))

Multiple values

if in any cases multiple values are needed :

CL-USER>(defun foo (&key a b c) (list a b c))
(NIL NIL NIL)
 
CL-USER>(foo :a 1)
(1 NIL NIL)
 
CL-USER>(foo :a 1 :c 3)
(1 NIL 3) 

Imagine a situation that the option has three parameters but you only want to assign value to one of them. Now if that one parameter is the first one, it is ok. but if you want to assign a value to the second or third parameter, what will you do? This the problem of optional parameters. Here we have another symbol which is call &key.

CL-USER>(defun function-name 
	(&rest args))

Please notice that any number of lisp expression can be part of defun. after you call the function they will be evaluated in order and the last expression is returned as the value of the function. If you want to immediately return anything anywhere in a function it is possible by using return-from.

defvar

There are two ways to create global variables in common lisp, defvar and defparameter. Their syntaxs are almost simple by taking variable name, an initial value and an optional documentation string. after that anywhere to refer to the current binding of the global variable. Notice that global variable's name start and end with *. It is important to mention that defparameter always assign the initial value while defvar does so only if the variable is undefined. We can say if you want to define a variable that you want to keep it even if later you made a change to the source you should use defvar.
By using defvar we can define global variable :

CL-USER>(defvar *total* 0)
CL-USER>(defun sum (&rest numbers)
CL-USER>(dolist (i numbers)
		(setf *total* (+ *total* I))
))

We will talk about setf and dolist later but for now you should know, setf can be used to setting the value to a variable dolist create a loop through a list

List

A list is a sequence. The very first element of the list is cons cell. If you want to build a list you should assemble some cons cells together.But before that we will show how you can define a list directly. To define a list we can use :

CL-USER>(list(max 2 3))

Also

CL-USER>(defvar *list* (list max 2 3))

To take the first element :

CL-USER>(first *)

To take the second element :

CL-USER>(second **)

Instead of * you can use the name of the list (here it is list).

Now let's back to cons. In the following example we will define a list after that you will se how we can do it with cons.

CL-USER>(list 1 2 3)
(1 2 3)
CL-USER>(cons 1 (cons 2(cons 3 nil)))
(1 2 3)


Now by combining the list and defun we will implement something that you can ask name and birth of people by using their place number in the list:

CL-USER>(defvar *db* ‘((anna 1987) (bob 1899) (charlie 1980)))
CL-USER>(defun name-and-birth-year (id)
	(values (first (nth (-id 1)
			*db*))
		 (second  (nth (-id 1)
			*db*))))

To call it :

CL-USER>(name-and-birth-year 2)

Or it is more beautiful to use it like :

CL-USER>(multiple-value-bind (name year)
	(name-and-birth-year 2)
	(format t “~a was born in ~a .~%name year))

Another example of using defun :

CL-USER>(defun football-player (name post team)
	(list :name name :post post :team team))

To add an example player to it :

CL-USER>(football-player “CR7” “Winger” “Manchester united)

If you want to check if something is a number you should use numberp If you want to check if a number is an even number you should use evenp If you want to check if a number is an odd number you should use oddp Remove-if-not is a function that can check a list. In the following example you will remove every number from the list if they Aren’t even :

CL-USER>(remove-if-not #’evenp(1 2 3 4 5 6 7 8 9))

Lambda function

If you want to define a function without giving it a name it could be possible by using lambda function. Lambda function is also known as anonymous functions.

CL-USER>(lambda (parameter)
	(body))

* The parameters are the variable in the expression
* The body is the mathematical logic expression
Consider the following example as lambda instance

CL-USER>(remove-if-not #’(lambda (x) (= 0 (mod x 2)))(1 2 3 4 5 6 7 8 9 10))
CL-USER>(mapcar (lambda (n) (/ n 2))(2 4 6))

if marco

The if macro is followed by a test clause that evaluates to t or nil.

CL-USER>(if test-form then-form [else-form])

Everytime the test-form evaluated, the then-form will be evaluated if the value of the test-form was non-NIL. Otherwise, the else-form value return. If condition is NIL and there's no else-form, then the IF returns NIL.
For example :

CL-USER>(setf a 10)
CL-USER>(if (> a 20)
 	(format t "~% a is less than 20")
	(format t "~% a is more than 20"))

For better understanding run these three codes in your lisp :

CL-USER>(if()
     ‘true
      ‘false)
 
CL-USER>(if(1)
     ‘true
      ‘false)
 
CL-USER>(if (oddp 5)
	‘odd-number
	‘even-number)

Unlike of other programming languages you can't excute multiple operation with then-form and else-form and both of them are restricted to a single one. But the good news is you can do a sequence of action with some other syntax.

Progn

If you want to do more than one thing in if form, you should use progn. Progn excutes different forms in order and returns the value of the last form.

CL-USER>(defun *number-was-odd nil)
 
CL-USER>(if (oddp 5)
	(progn (setf (number-was-odd t)
		‘odd-number)
	‘even-number)

When & Unless

Instead of using progn, you can use when and unless. With when , all the enclosed expressions are evaluated when the condition is true. With unless , all the enclosed expressions are evaluated when the condition is false.

CL-USER>(defvar *number-is-odd* nil)
 
CL-USER>(when (oddp 5)
	(setf *number-is-odd* t)
	'odd-number)
 
 
CL-USER>(unless (oddp 4)
	(setf *number-is-odd* nil)
	'even-number)

Cond

The problem is these commands can’t do anything when the condition evaluates in the opposite way; they just return nil and do nothing. If you want to anything you can use cond macro.

CL-USER>(setf *num* 7)
CL-USER>(cond 
	   ((> num 0)
		(format t” number is positive”)
		(format t “number is ~a %” num))
	   ((< num 0)
		(format t” number is negative”)
		(format t “number is ~a %” num))
	   ((= num 0)
		(format t “number is ~a %” num))))
**defparameter**
\\
\\
CL-USER>(defparameter *fruit* 'apple)
CL-USER>(cond ((eq *fruit* 'apple) 'its-an-apple)
	  ((eq *fruit* 'orange) 'its-an-orange))

Case

Another lisp command form that can handle different conditions is case that is easier to use.

CL-USER>setq day 4)
CL-USER>(case day
	   (1 (format t "~% Monday"))
	   (2 (format t "~% Tuesday"))
	   (3 (format t "~% Wednesday"))
	   (4 (format t "~% Thursday"))
	   (5 (format t "~% Friday"))
	   (6 (format t "~% Saturday"))
	   (7 (format t "~% Sunday")))
 
CL-USER>(setq val1 2)
CL-USER>(<code lisp>case val1
	   (1 (format t "you selected number 1"))
	   (2 (format t "you selected number 2"))
	   (3 (format t "you selected number 3"))
	   (4 (format t "you selected number 4"))
	   (5 (format t "you selected number 5"))
)

And & Or

And and Or operators give true or false.

CL-USER>(and (oddp 5) (oddp 7) (oddp 9))
CL-USER>(or (oddp 4) (oddp 7) (oddp 8))

Loop in lisp

There are some looping constructions in the lisp. For example, loop, dolist, dotimes and do.

In the following you will find some examples of using loop. Its Structure is easy and doesn’t need any extra explanation.

Loop

CL-USER>(loop 
	   body-form*)
 
CL-USER>(loop for i
	   below 5
	   do (print I))
 
CL-USER>(loop for I
	   from 1 to 10 summing (expt x 2))
 
CL-USER>(setq a 10)
CL-USER>(loop 
   	   (setq a (+ a 1))
   	   (write a)
   	   (when (> a 17) (return a))
)

Dolist

dolist will loop across the item of the list. It is important to mention that the body-form will be evaluated for each item in the list.

CL-USER>(dolist (var list-form)
	    body-form*)
CL-USER>(dolist (x ‘(1 2 3)) (print x))
 
CL-USER>(dolist (n '(1 2 3 4 5 6 7 8 9))
            (format t "~% Number: ~d Square: ~d" n (* n n))
)

Dotimes

With dotimes you can do looping for some fixed number of iterations.

CL-USER>(dotimes (var count-form)
	   (body-form*)
CL-USER>(dotimes (I 4)
	(print I))
 
 
CL-USER>(dotimes (n 11)
   	(print n) (prin1 (* n n))
)

Do

Do is more general than two others.

CL-USER>(do ((x 0 (+ 2 x))
  	      (y 20 ( - y 2)))
  	      ((= x y)(- x y))
  	      (format t "~% x = ~d  y = ~d" x y)
)

Using collect to return a list :

CL-USER>(loop for x in ‘(1 2 3)
	collect (* x 10))

Defmarco

One of the greatest thing about lisp is that you can extend the syntax by using defmacro. The difference between defmacro and defun is defun returning values, but the defmacro will return a lisp form.

CL-USER>(defmacro macro-name (parameter*)
           "Optional documentation string."
           body-form*)


HASH TABLE

A collection of key-values pairs. It uses the key to access the elements in the collection. Anytime you need to access to some elements only by using a key you can use hash table.
By using make-hash-table you can create a hash table.

CL-USER>(defparameter Team (make-hash-table))

Set the number of 7 to CR7 and 18 to Paul schools:

CL-USER>(setf (gethash '7 Team) '(CR7))
CL-USER>(setf (gethash '18 Team) '(Paul schools))

By using gethash it is possible to get the value that is stored in the key 7:

CL-USER>(gethash '7 Team)

maphash will run a function on the entire of hash table:

CL-USER>(maphash #'(lambda (k v) (format t "~a = ~a~%" k v)) Team)

If you want to remove on entry, it is possible by using remhash:

CL-USER>(remhash '18 Team)

Defclass
By using defclass you can define your own classes.

CL-USER>(defclass name (superclass-name*)
            (slot-specifier*))

In the following lines you will find some examples:

CL-USER>(defclass Team ()
	   (color
	    country))

If you want to make an example of team it is possible by using make-instance:

CL-USER>(defparameter *Man utd* (make-instance 'Team))

Set the values for Man utd :

CL-USER>(setf (slot-value *Team* 'color) "Red")
CL-USER>(setf (slot-value *Team* 'country) "England")

You can also get the value if you want :

CL-USER>(format t "Man utd is ~a and is playing in ~a ~%" 
	    (slot-value *Team* 'color) 
	    (slot-value *Team* 'country))

In defclass we have some options:
- initarg : New instance can be constructed
- initform : Default value for the instance
- accessor : It is both a getter and a setter

CL-USER>(defclass Team ()
	((name
		:initarg :name
		:initform (error "Must provide a name"))
	(color
		:initarg :sound
		:initform "No color set"
		:accessor Team-color)
	)
)


For example :

CL-USER>(defparameter *Man utd*
	(make-instance 'Team :name "Man utd" :color "red"))

As always we get the output like this :

CL-USER>(format t "~a is ~a ~%" 
	(slot-value *man utd* 'name) 
	(slot-value *man utd* 'color))

Another example for defclass is:

CL-USER>(defclass shape ()
           ((color :accessor get-shape-color
                   :initarg :set-color)
            (center :accessor shape-center
                    :initarg :center
                    :initform '(0 . 0))))
CL-USER>(defvar *red-shape* (make-instance 'shape :set-color 'red))

We will define another class and give the shape class as superclass to it :

CL-USER>(defclass circle (shape)
           ((radius :initarg :radius)))

circle will be one instance of circle class. We define the color and radius for our instance. later by using radius we can calculate the are of the circle. However before that we should define a method that with which you can compute the are.

CL-USER> (defvar *circle*
           (make-instance 'circle :set-color 'green :radius 10))

First you can run this method on your repl. However for sure for calculating the area we need more information about the shape!

CL-USER> (defmethod area ((obj shape))
           (error "We need more information about OBJ to know its area"))

Here we define the method that can compute the area of a circle.

CL-USER> (defmethod area ((obj circle))
           (* pi (expt (slot-value obj 'radius) 2)))

Now by calling the method we can compute the circle instance that we defined before. You can define more methods for different shape for example, triangle.

CL-USER> (area *circle*)

The NIL

First please look at this example. Can you recognize why the output is true?

CL-USER> (if '(1)
           (print "true")
           (print "false"))
"true" 
"true"

To know why '(1) was considered as true value you should know the output will be true for any value that it is not equivalent to an empty list. But what about false… . In common lisp false symbol is NIL. There are four type of NIL in the common lisp. All of the following expressions are considered as empty list and so NIL:
'(), (), 'nil and nil. You can check the equivalency of them like this two by two:

CL-USER> (eq '() nil)

Let & Let*

Backquote and comma