(and (keep calm) (hack lisp))
2015-07-05Last modified on 2021-05-23
Hello there !
I made a small presentation about lisp at a functional programming event at SFEIR. In fact, it was more an intro than "hacking" into it.
This post explains a few things and some examples I used during this talk.
The slides are here.
First, I introduced John McCarthy (the guy who invented lisp) and Dennis Ritchie (you should know this guy, who admired lisp). They died in october 2011, I just wanted the audience to remember that Steve Jobs is not the only guy who died at this time...
Then, I talked about lisp, the spec and some implementations.
And Polish notation (Let me wikipedia that for you).
With a nice clisp REPL open, I started showing a few examples (
> represent the REPL input):
> (print "Hello World !") "Hello World !" "Hello World !"
Why is "Hello World !" printed 2 times ?
Because everything returns something. The
> (+ (print 1) (print 2)) 1 2 3
which print 1, then 2, and finally the computation of
(+ 1 2) which is 3.
I explained the differences between
defvar and defparameter
defparameter are used to set variables. The latter one is, as I read, used for values that can have an effect on the program (I took the example of a ratio that can be modified and used in function bodies).
> (defvar *kikoo* "plop") *KIKOO* > *kikoo* "plop"
Used for constants ! I used the following code to show the re-assignment warning, and to show that the final value was "plip".
> (defconstant *const* "plop") > (defconstant *const* "plip") > *const* "plip"
I used the following code to describe how setq works for multiple variables and computations.
> (defvar a) A > (defvar b) B > (defvar c) C > (setq a 1 b 2 c 3) 3 > (setq a (+ 1 b) b (+ 1 a) c (+ a b)) 7
I should also have talked about let* but I forgot what was the difference... The last
x is not defined since the let declaration is scoped, so I got an error.
> (let ((x 1) (y 2)) (+ x y)) 3 > x *** - SYSTEM::READ-EVAL-PRINT: variable X has no value Rentrées possibles: USE-VALUE :R1 Input a value to be used instead of X. STORE-VALUE :R2 Input a new value for X. ABORT :R3 Abort main loop
I created 2 functions, a good old "hello world" and one with a parameter. Note that when defining a function, the name of the function is returned.
> (defun hello-world () (print "Hello, World!")) HELLO-WORLD > (hello-world) "Hello World !" "Hello World !"
I used format instead of print to introduce
NIL (format doesn't return the data, but the
> (defun hello-toto (name) (format t "Hello, ~a" name)) HELLO-TOTO > (hello-toto "彩子") Hello, 彩子 NIL
They are used to "apply" a function to an arguments list. I chose to also introduced a lambda function.
> (funcall (lambda (x) (+ x 3)) 4) 7
Conditions and predicates
I introduced quickly
if and the über powered alternative
cond. Also, predicates for everythings !
> (defun test-thing (thing) (print (if thing "yep" "nope"))) TEST-THING > (test-thing "plop") "yep" > (test-thing NIL) "nope"
I didn't talk about them. Next time !
Lisp stands for LISt Processing
Why choose a lisp instead of everything else ? List manipulations are one of lisp's super powers.
I introduced cons and the quote operator.
> (cons 1 (cons 2 (cons 3 (cons 4 nil)))) (1 2 3 4) > '(1 2 3 4) (1 2 3 4)
> (car '(1 2 3)) 1
And its buddy
> (cdr '(1 2 3)) (2 3)
> (mapcar (lambda (x) (* x 2)) '(1 2 3 4 5)) (2 4 6 8 10)
quote or '
In lisp, code is data ! You can use quote to not evaluate a list (in the second example, setq is not processed).
> (setq a 3) 3 > '(setq a 3) (SETQ A 3)
backquote / quasiquote and comma
Quasiquote is like the previous quote, but you can use comma , to evaluate the following expression:
> (let ((s 'hello)) `(,s world)) (HELLO WORLD)
> (mapcar #'sqrt '(1 2 3 4 5))
> (defmacro let1 (var val &body body) `(let ((,var ,val)) ,@body)) LET1
Allows to understand in a simple way the macro code. In this example:
> (let1 foo (+ 2 3) (princ "Lisp is awesome!") (* foo foo))
(+ 2 3)
(princ "Lisp is awesome!")and
(* foo foo)
The macro body (after the quasiquote) shows that we use the evaluated values of
val in a
let. So we define a variable with the name
foo and the value
(+ 2 3).
body is evaluated:
(princ "Lisp is awesome!")prints
Lisp is awesome!
(* foo foo)is evaluated to
(* (+ 2 3) (+ 2 3))and prints
Shows the expanded code from the macro, and returns
T (true) if it has been expanded:
> (macroexpand '(let1 foo (+ 2 3) (* foo foo))) (LET ((FOO (+ 2 3))) (* FOO FOO)) ; T
How to macros ?
(Maquereau is the french word for Mackerel)
- write sample call and expansion
- write generative code
- prevent leaks
I concluded this introduction to lisp saying that it is awesome, and even if I can't use it professionally, it's pretty interesting to play with it.
Also, I recommend reading: