In the first article in this series, I discussed the basics of CommonLISP, including the installation of the runtime, mathematical operations, and variables. In this article, I will be detailing more operations which one will encounter while building applications in CommonLISP, such as standard output, conditional statements, lists, functions, and macros.
Standard output can be achieved by calling the print function on the desired output. However, the output will include quotation marks for strings. String values can be printed without quotation marks by calling the write or write-line functions on them instead. write-line will insert a new-line after the output whereas write will not.
Code -> Output
(print “Hello World”) -> “Hello World” (print (+ 22 22)) -> 44
The if statement is the way that LISP handles conditional statements.
It takes 3 arguments, the first is the condition, the second is what is to be returned from the function if it evaluates to be true, and the third is what is to be returned from the function if it isn’t true.
Note: all values outside of nil are considered to be true.
(if (>5 1) (print “5 is greater than 1”) (print “Something is wrong”) )
This code will always print "5 is greater than 1", and will never print "Something is wrong".
By default, if statements only allow one line of code for each condition. This becomes a problem if the programmer needs to include side effects in addition to the return statement. The solution to this issue is the
progn function. The
progn function takes an undetermined amount of arguments, referred to as the “body”, and the last argument will be the return statement of the function.
Progn works similar to how curly brackets work in C based languages.
(if (> 5 1) (progn (print “everything is right”) (+ 5 1) ) (progn (print “something is wrong”) (- 5 1) ) )
This program will check to make sure that 5 >1.
If it is, it will print “everything is right” and then return 5+1.
If it isn’t, it will print “something is wrong”, and then return 5-1.
One of the unique features of LISP is how easy it is to create linked lists. A list is created by using what is called the symbol operator on a list of items surrounded by paren and separated by spaces. The items can be of any data type.
Example = Linked List
‘(1 2 3 4) = 1 -> 2 -> 3 -> 4 ‘(“Hello” 2 “Friend, I am Cole” 3) = “Hello” -> 2 -> “Friend, I am Cole” -> 3 ‘(2 3 4 5.5) = 2 -> 3 -> 4 -> 5.5
Some of the most common functions used for operating on lists in LISP are car and cdr. Car returns the first element of a list. Cdr returns every following element.
Example -> Returns
(car ‘(1 2 3 4)) -> 1 (cdr ‘(1 2 3 4)) -> (2 3 4) (cdr (cdr ‘(1 2 3 4))) -> (3 4) (car (cdr ‘(1 2 3 4))) -> 2
The simplest form of a loop is with the loop keyword. It takes a set of statements as its arguments, and will repeat them until it encounters a return statement.
(defvar a) (setf a 0) (loop (setf a (+ a 1)) (write a) (when (> a 4) (return a))
This example declares the variable "a", sets it to 0, then each loop, it will add 1 to a, and print it with the write command. When a > 4, it will exit the loop and return a.
Functions in CommonLISP are defined by the
The syntax is
(defun <function name> (<parameter list separated by spaces>) (<function body, last value is the return value>) )
Calling the function is the same as any of the above operators.
For example, here is a function which will return the square of the parameter “toBeSquared”.
(defun squareNum (toBeSquared) (* toBeSquared toBeSquared))
Example -> Return Value
(squareNum 3) -> 9
(squareNum (squareNum 2)) -> 16
CommonLISP provides a way to create anonymous functions, which will only be run once, when they are encountered. They will not be given a name nor will they be stored for later use. The syntax is identical to defun, but with the defun keyword swapped out for lambda.
(+ 2 ((lambda (a) (+ a a) 2))
Macros are what make LISP such a uniquely powerful language. A macro is a function whose body is interpreted as input for the program before being interpreted as a program. It allows developers to programmatically change the program which is to be run. Macros are the reason as to why LISP is such a powerful tool in AI, they allow the computer to remember past decisions and modify its own code.
In other words, LISP adds a step before compilation, called “macro-expansion”. The macro-expansion step compiles the macro into lisp code before executing the rest of the program.
Macros are defined using the
The syntax is
<defmacro> <name> (parameters) <body-form>
Macros are complex, so I will give a simple example.
(defmacro eight () (+ 3 5)) (+ eight 8) -> will return 16.
Whenever the above macro (eight) is called, it will be treated as the number 8, since it is going to be compiled and evaluated before running elsewhere.