Lisp
Introduction
This is a quick tour on lisp. I decided to look at this because of the build a compiler youtube by lens_r which made me feel I am missing something. This has been rabbit hole which I have fallen done
Concepts
This is my view and maybe wrong but to me the first thing I noticed was the huge amount of parentheses which are involved. It made the language look really ugly and made me feel don't do this. I think I have touched this in the past because of a gun to my head. That said, like people, you probably need to understand before having a view, and even then, not for you is a better view and it is negative. So here is the half day I spent
Comments
;;;; Describe Program 4 semi colons
;;; Comments
;; Indented Comments
#|| Multiline
My Comments
||#
Format to terminal
(format t "Hello World ~%")
(print "Hello World")
Variables
To declare
(defvar *my-variable* "Hello World" )
It is common practice for local variable to have asterixes
We can declare variables for functions too, in this case read-data now is the built-in read function.
(defvar *read-data* (read))
Functions
We can of course define functions. So putting the above together we are prompted for a value and it prints it to the terminal. Not the ~% is the linefeed in list and ~a is a formatter like printf
(defvar *read-data* (read))
(defun read-and-print (name)
(format t "Read and Print value is ~a ~%" name))
(read-and-print *read-data*)
Changing values of variables
We use setf to change the values of existing variables
(defvar *read-data* (read))
;; You can change a value using setf
(setf *read-data* "Hello World 1")
(read-and-print *read-data*)
(setf *read-data* "Hello World 2")
(read-and-print *read-data*)
Formatting
This is like printf
(format t "PI to 5 characters is ~5f ~%" 3.14159)
(format t "PI to 4 decimal places is ~,4f ~%" 3.14159)
Cells
A Cell, I think is a set of parentheses and we can embed them inside each other. So
(format t "Text with this ~d ~%" (+ 5 4))
; Add a cell within a cell
(format t "Text with this ~d ~%" (+ 5 (+ 4 3)))
;; and again
(format t "Text with this ~d ~%" (+ 5 (+ 4 (+ 100 5))))
Maths Stuff
Just some examples. This is a whirlwind tour not a tutorial
(format t "Modulus of 10/3 is ~d ~%" (mod 10 3))
(format t "Remainder of 10/3 is ~d ~%" (rem 10 3))
;; All work the same way e.g. sqrt
(format t "Square root of 9 is ~d ~%" (sqrt 9))
;; and floor
(format t "Floor of 9.9 is ~d ~%" (floor 9.9))
The blasted quote
I had to read about this because of my stuffed up brain. In lisp there is some referred to as a quote. And they kept mentioning shorthand but they were incredible unclear what for. and it what the function quote. What they meant is ` means quote ()
(format t "Quote is ~a ~%" (+ 1 2)) ; Quote is 3
(format t "Quote is ~a ~%" (quote (+ 1 2))) ; Quote is (+ 1 2)
(format t "Quote is ~a ~%" `(+ 1 2)) ; Quote is (+ 1 2)
Equality
Equality in Lisp has three approaches
- For symbols we use eq
- For numbers we use =
- For strings we use equal
;; Symbols
(format t "Are 'hello' and 'hello' equal? ~a ~%" (eq 'hello 'hello))
;; Numbers
(format t "Are 1 and 1 equal? ~a ~%" (= 1 1)) ; T
(format t "Are 1 and 2 equal? ~a ~%" (= 1 2)) ; NIL
;; Strings
(format t "Are 'hello' and 'hello' equal? ~a ~%" (equal "hello" "hello"))
We can compare things with the same value but presented differently with equalp
;; equalp is used to compare numbers
(format t "Are 1 and 1.0 equal? ~a ~%" (equalp 1 1.0)) ;T
(format t "Are 1.01 and 1.010 equal? ~a ~%" (equalp 1.01 1.010)) ;T
(format t "Are 1.010 and 1.01 equal? ~a ~%" (equalp 1.010 1.01)) ;T
;; for strings for case insensitive
(format t "Are 'hello' and 'HELLO' equal? ~a ~%" (equalp "hello" "HELLO")) ;T
Lists
Seemed a big deal in Lisp. I guess most of this is self explanatory
Simple Lists
;; Create a list
(defvar *my-list* (list 0 1 2 3 4 5))
;; Print the list
(format t "List is ~a ~%" *my-list*)
;; Get the first element
(format t "First element is ~a ~%" (first *my-list*))
;; Get the rest of the list
(format t "Rest of the list is ~a ~%" (rest *my-list*))
;; Get the second element
(format t "Second element is ~a ~%" (second *my-list*))
;; Get the third element
(format t "Third element is ~a ~%" (third *my-list*))
;; Using nth
(format t "Third element is ~a ~%" (nth 2 *my-list*))
;; Using car
(format t "First element is ~a ~%" (car *my-list*))
;; Using cdr
(format t "Rest of the list is ~a ~%" (cdr *my-list*))
;; Using cadr (get first element of rest)
(format t "Second element is ~a ~%" (cadr *my-list*))
;; Using caddr (get second element of rest)
(format t "Third element is ~a ~%" (caddr *my-list*))
;; Using caddr (get third element of rest)
(format t "Fourth element is ~a ~%" (cadddr *my-list*))
;; Are we a list?
(format t "Is a list? ~a ~%" (listp *my-list*))
;; Is value a list?
(format t "Is a list? ~a ~%" (listp 1))
;; Append to a list
(format t "Append to list ~a ~%" (append *my-list* (list 6 7 8 9 10)))
;; Concatenate lists
(format t "Concatenate lists ~a ~%" (concatenate 'list *my-list* (list 6 7 8 9 10)))
;; Reverse a list
(format t "Reverse list ~a ~%" (reverse *my-list*))
;; Sort a list
(format t "Sort list ~a ~%" (sort *my-list* #'<))
;; Create a list of lists
(defvar *my-list-of-lists* '((1 2 3) (4 5 6) (7 8 9)))
;; Remove duplicates
(format t "Remove duplicates ~a ~%" (remove-duplicates (list 1 1 2 2 3 3 4 4 5 5)))
Association list or A-list
The minute they use a fancy word I get stuffed and have to google. So I think what they mean is a list with key value having a key and a value. They go on about car and cdr
(defparameter *my-heroes* `( (superman . "Clark Kent")
(batman . "Bruce Wayne")
(spiderman . "Peter Parker")))
; List is ((SUPERMAN . Clark Kent) (BATMAN . Bruce Wayne) (SPIDERMAN . Peter Parker))
(format t "List is ~a ~%" *my-heroes*)
; Assoc (SUPERMAN . Clark Kent)
(format t "Assoc ~a ~%" (assoc 'superman *my-heroes*))
Another approach to achieve the same thing
;; second approach wih cons
(defparameter *marks* (list (cons 'kishan 96) (cons 'saksham 92)))
;2 List is ((KISHAN . 96) (SAKSHAM . 92))
(format t "2 List is ~a ~%" *marks*)
;2 Assoc (KISHAN . 96)
(format t "2 Assoc ~a ~%" (assoc 'kishan *marks*))
Functions 2
Here some examples
Simple example
;; Get average
(defun get-average (a b)
(/ (+ a b) 2))
(format t "Average is ~a ~%" (get-average 10 20))
Multiple Arguments
We can simulate vargs
;; Rest parameters is like varargs
(defun get-average-rest (&rest numbers)
(/ (apply #'+ numbers) (length numbers)))
(format t "Average is ~a ~%" (get-average-rest 10 20 30 40 50))
Optional Arguments
Here we can either pass b or not
(defun get-average-optional (a &optional b)
(if b
(/ (+ a b) 2)
a))
; Average is with B 15
(format t "Average is with B ~a ~%" (get-average-optional 10 20))
; Average is without B 10
(format t "Average is without B ~a ~%" (get-average-optional 10))
Return value
By default the return value is the last statement executed. To override this we use the keyword return-from and the function name
(defun get-average-return (a b)
(return-from get-average-return (/ (+ a b) 2)))
Flow Control
This is why I am doing this because of the word continuation. Here are some lispy controls
If Statements
;; If statements are written as follows, if true then do this else do this
(if (= 1 1)
(format t "1 is equal to 1 ~%")
(format t "1 is not equal to 1 ~%"))
;; Not equal
(if (not (= 1 1))
(format t "1 is equal to 1 ~%")
(format t "1 is not equal to 1 ~%"))
;; And
(if (and (= 1 1) (= 2 2))
(format t "1 is equal to 1 and 2 is equal to 2 ~%")
(format t "1 is not equal to 1 and 2 is not equal to 2 ~%"))
;; And or haha
(if (or (= 1 1) (= 2 2))
(format t "1 is equal to 1 or 2 is equal to 2 ~%")
(format t "1 is not equal to 1 or 2 is not equal to 2 ~%"))
;; Multiple statements with progn
(progn
(format t "Hello ~%")
(format t "World ~%"))
;; Used with if
(if (and (= 1 1) (= 2 2))
(progn
(format t "1 is equal to 1 and 2 is equal to 2 ~%")
(format t "Hello ~%")
(format t "World ~%"))
(format t "1 is not equal to 1 and 2 is not equal to 2 ~%"))
Case Statements
(case 1
(1 (format t "1 ~%"))
(2 (format t "2 ~%"))
(3 (format t "3 ~%"))
(t (format t "Not 1, 2 or 3 ~%")))
When, Unless and Loops
;; When
(when (= 1 1)
(format t "1 is equal to 1 ~%"))
;; Unless
(unless (= 1 1)
(format t "1 is not equal to 1 ~%"))
;; Loops
;; Loop with for
(loop for i from 1 to 10
do (format t "Hello ~%"))
;; Loop with repeat
(loop repeat 10
do (format t "Hello ~%"))
;; dotimes
(dotimes (i 10)
(format t "Hello ~%"))
cond
Like this one
;; Using cond
(cond
((= 1 1) (format t "1 is equal to 1 ~%"))
((= 2 2) (format t "2 is equal to 2 ~%"))
(t (format t "Not 1 or 2 ~%")))