Lisp: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
 
(82 intermediate revisions by the same user not shown)
Line 1: Line 1:
=Introduction=
=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
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
=Useful Links=
Not gonna type forever whilst someone else already has. I remember by typing but here is a more professional approach [https://www.lispworks.com/documentation/HyperSpec/Front/Contents.htm Lisp Works]
=Concepts=
=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
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<br>
<br>
I have a lot of trouble reading the manuals for anything. YouTube has been a god send for me along with examples. If there are youtuber out there please make a video on how to read the manual. Probably all me but this is written in greek to me. I probably give up too easily<br><br>
'''flet''' ((function-name lambda-list <nowiki>[[</nowiki>local-declaration'''*''' | local-documentation<nowiki>]]</nowiki> local-form'''*''')'''*''') declaration'''*''' form'''*'''


=Comments=
=Comments=
Line 176: Line 182:
(format t "Remove duplicates ~a ~%" (remove-duplicates (list 1 1 2 2 3 3 4 4 5 5)))
(format t "Remove duplicates ~a ~%" (remove-duplicates (list 1 1 2 2 3 3 4 4 5 5)))
</syntaxhighlight>
</syntaxhighlight>
==Splicing==
Not sure my odds of remembering. The '''@''' after a comma within quote - yes I know, then the form following the at-sign is evaluated to produce a list of objects
<syntaxhighlight lang="lisp">
;; Create a list
(defvar *my-list* (list 0 1 2 3 4 5))
;; a reminder of rest which mean everything but the first like javascript
(format t "List with rest is ~a ~%" (rest *my-list*))
;; Splice a list
;; List with 0 is (0 1 2 3 4 5)
(format t "List with 0 is ~a ~%" `(0 ,@(rest *my-list*)))
;; List with 2 is (2 1 2 3 4 5)
(format t "List with 2 is ~a ~%" `(2 ,@(rest *my-list*)))
</syntaxhighlight>
=Association list or A-list=
=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'''
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'''
Line 199: Line 223:
;2 Assoc (KISHAN . 96)  
;2 Assoc (KISHAN . 96)  
(format t "2 Assoc ~a ~%" (assoc 'kishan *marks*))
(format t "2 Assoc ~a ~%" (assoc 'kishan *marks*))
</syntaxhighlight>
=Functions 2=
Here some examples
==Simple example==
<syntaxhighlight lang="lisp">
;; Get average
(defun get-average (a b)
  (/ (+ a b) 2))
(format t "Average is ~a ~%" (get-average 10 20))
</syntaxhighlight>
==Multiple Arguments==
We can simulate vargs
<syntaxhighlight lang="lisp">
;; 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))
</syntaxhighlight>
==Optional Arguments==
Here we can either pass b or not
<syntaxhighlight lang="lisp">
(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))
</syntaxhighlight>
==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
<syntaxhighlight lang="lisp">
(defun get-average-return (a b)
  (return-from get-average-return (/ (+ a b) 2)))
</syntaxhighlight>
=Flow Control=
This is why I am doing this because of the word continuation. Here are some lispy controls
==If Statements==
For if statements [[#Special Forms|Special Forms]]
==Case Statements==
<syntaxhighlight lang="lisp">
(case 1
  (1 (format t "1 ~%"))
  (2 (format t "2 ~%"))
  (3 (format t "3 ~%"))
  (t (format t "Not 1, 2 or 3 ~%")))
</syntaxhighlight>
==When, Unless and Loops==
<syntaxhighlight lang="lisp">
;; 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 ~%"))
</syntaxhighlight>
==cond==
Like this one
<syntaxhighlight lang="lisp">
;; 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 ~%"))) 
</syntaxhighlight>
=Fun with Cars=
==car==
So for car this is simple
<syntaxhighlight lang="lisp">
(defvar *my-list* (list 0 1 2 3 4 5))
; Returns first element in list i.e. 0
(format t "First element is ~a ~%" (car *my-list*))
</syntaxhighlight>
==cdr (pronounced cudder)==
So for cdr is just the rest
<syntaxhighlight lang="lisp">
(defvar *my-list* (list 0 1 2 3 4 5))
; Returns rest of the elements in list i.e. 1 2 3 4 5
(format t "First element is ~a ~%" (cdr *my-list*))
</syntaxhighlight>
==All the combinations==
Found a page which seems to explain the unexplainable. To understand the terms now we need to understand
<br>
{| class="wikitable"
|-
|This place ...
|Is equivalent to this place ...
|-
|(caar x)
|(car (car x))
|-
|(cadr x)
|(car (cdr x))
|-
|(cdar x)
|(cdr (car x))
|-
|(cddr x)
|(cdr (cdr x))
|-
|(caaar x)
|(car (car (car x)))
|-
|(caadr x)
|(car (car (cdr x)))
|-
|(cadar x)
|(car (cdr (car x)))
|-
|(caddr x)
|(car (cdr (cdr x)))
|-
|(cdaar x)
|(cdr (car (car x)))
|-
|(cdadr x)
|(cdr (car (cdr x)))
|-
|(cddar x)
|(cdr (cdr (car x)))
|-
|(cdddr x)
|(cdr (cdr (cdr x)))
|-
|(caaaar x)
|(car (car (car (car x))))
|-
|(caaadr x)
|(car (car (car (cdr x))))
|-
|(caadar x)
|(car (car (cdr (car x))))
|-
|(caaddr x)
|(car (car (cdr (cdr x))))
|-
|(cadaar x)
|(car (cdr (car (car x))))
|-
|(cadadr x)
|(car (cdr (car (cdr x))))
|-
|(caddar x)
|(car (cdr (cdr (car x))))
|-
|(cadddr x)
|(car (cdr (cdr (cdr x))))
|-
|(cdaaar x)
|(cdr (car (car (car x))))
|-
|(cdaadr x)
|(cdr (car (car (cdr x))))
|-
|(cdadar x)
|(cdr (car (cdr (car x))))
|-
|(cdaddr x)
|(cdr (car (cdr (cdr x))))
|-
|(cddaar x)
|(cdr (cdr (car (car x))))
|-
|(cddadr x)
|(cdr (cdr (car (cdr x))))
|-
|(cdddar x)
|(cdr (cdr (cdr (car x))))
|-
|(cddddr x)
|(cdr (cdr (cdr (cdr x))))
|}
=Functions 3=
A while ago we did lists and they had this insane thing called caar, cadar, cddar
as Car of Car and gets the '''car''' of '''car''' or the first item in the list
*caar is (car (car x))
*cadar is (car (cdr (car x)))
*cddar is (cdr (cdr (car x)))
==caar==
(car (car x))<br>
From inside to outside<br>
First item = (superman (6 ft 3 in) ( 230 lbs))<br>
And first item of this = superman<br>
==cadar==
(car (cdr (car x)))<br>
From inside to outside<br>
First item = (superman (6 ft 3 in) ( 230 lbs))<br>
rest of items = (6 ft 3 in) ( 230 lbs))<br>
first item (6 ft 3 in)<br>
==cddar==
(cdr (cdr (car x)))<br>
From inside to outside<br>
First item = (superman (6 ft 3 in) ( 230 lbs))<br>
rest of items = (6 ft 3 in) ( 230 lbs))<br>
rest of items = ( 230 lbs))<br>
<syntaxhighlight lang="lisp">
(defparameter *my-heroes* `( (superman (6 ft 3 in) ( 230 lbs))
                            (batman  (6 ft 0 in) ( 190 lbs))
                            (spiderman (6 ft 2 in) ( 210 lbs))))
(defun get-heroes-data (size)
    (format t "Heroes ~a ~%"
        `(,(caar size) is ,(cadar size), (cddar size))))
; Heroes (cdr (cdr (car x)))(Superman Is (6 Ft 3 In) ((230 Lbs)))
(get-heroes-data *my-heroes*)
</syntaxhighlight>
=Mapping over a list=
Here we map over a function, in this case numberp
<syntaxhighlight lang='lisp'>
;; mapcar example of using a function
;; mapcar List is (T T T Nil Nil)
(format t "mapcar List is ~a ~%" (mapcar #'numberp  `(1 2 3 g d)))
</syntaxhighlight>
=Lambda=
Lambda is a way of defining an anonymous function in lisp. We can pass functions to mapcar using the hash quote e.g. #`
<syntaxhighlight lang='lisp'>
; mapcar List is (3 6 9 12 15)
(format t "mapcar List is ~a ~%" (mapcar #'(lambda (x) (* 3 x)) '(1 2 3 4 5)))
</syntaxhighlight>
<br>
Got confused with this because on the use of print
<syntaxhighlight lang='lisp'>
(mapcar #'(lambda (x) (print (* 3 x))) '(1 2 3 4 5))
</syntaxhighlight>
Guess this the equivalent of
<syntaxhighlight lang='js'>
[1, 2, 3, 4, 5].map((n)=> console.log(n))
</syntaxhighlight>
And
<syntaxhighlight lang='js'>
// mapcar List is [1, 2, 3, 4, 5]
console.log('mapcar List is %o',  [1, 2, 3, 4, 5].map((n)=> n))
</syntaxhighlight>
=multiple-value-bind=
Not too sure what a macro is, but that is what this is. I suspect it is a way of extending existing functionality. This is an example of calling a function which returns two values. To do this we use the accessor values
<syntaxhighlight lang='lisp'>
(defun expose-me (num)
    (values (expt num 2) (expt num 3)))
;; Example of multiple value call
(multiple-value-bind (arg-a arg-b) (expose-me 2)
    (format t "2^2 = ~d 2^3 = ~d~%" arg-a arg-b))
</syntaxhighlight>
=Macros=
==Example 1==
This is taken from [https://www.geeksforgeeks.org/macros-in-lisp/ geeksforgeeks] and does seem easy to understand however here is the quote from another page. A macro is an ordinary piece of Lisp code that operates on another piece of putative Lisp code, translating it into (a version closer to) executable Lisp.
<syntaxhighlight lang='lisp'>
(defmacro sumup (a b)
    ; This line will be executed whenever
      ; we use the macro sum
    ; with two integer parameters
    (format t "~D + ~D : ~D" a b (+ a b))
)
; Calling macro sumup with parameters 7 and 18
(sumup 7 18)
(terpri)
</syntaxhighlight>
So done with all that and my good friend Derek Banas sorts the Greek out for me. He explained that a common problem my be that you have to often have
multiple lines in an if statement and it can be annoying to use progn all of the time to do this. (When I think of C and macro usage in it, it smacks of the same problem. <br><br>
Here is an example of the problem '''not''' the example
<syntaxhighlight lang='lisp'>
(defvar *num* 2)
(defvar *num-2* 0)
(if (= *num* 2)
    (progn
      (setf *num-2* 3)
      (format t "num-2 is ~d ~%" *num-2*)
    )
    (format t "Not equal to 2 ~%"))
</syntaxhighlight>
So with macros we need to have it generate code not be code like we do in C<br>
<syntaxhighlight lang='lisp'>
(defmacro ifit (condition &rest body)
    `(if ,condition
        (progn
            ,@body)
        (format t "Can't Drive ~%"))
)
(setf *age* 18)
(ifit (>= *age* 18)
    (format t "Line one of lisp ~%")
    (format t "Line two of Lisp ~%")
    (format t "Line three of Lisp ~%")
    (terpri)
)
</syntaxhighlight>
In the macro we use quasi quoting which is where we switch between code and data using the comma for expression and ,@ for the multiple lines. This replacing the '''condition''' and '''body''' with the quoted value not the evaluated value.
==Example 2==
I am not feeling the love with second example. I will have to use some of this to appreciate it I think. It is just like C I think so just a way to generate repetitive code where the language is to granular.
<syntaxhighlight lang='lisp'>
;; Function to add two numbers
(defun add (a b)
    (let ((sum (+ a b)))
        (format t "Sum of ~d and ~d is ~d ~%" a b sum)
        sum)
)
;; Create a macro to add two numbers
(defmacro letx (var val &rest body)
    `(let ((,var ,val))
        ,@body)
)
;; define a function to use letx
(defun addx (a b)
    (letx sum (+ a b)
        (format t "Sum of ~d and ~d is ~d ~%" a b sum)
        sum)
)
;; Call the function
(addx 2 3)
</syntaxhighlight>
=Classes In Lisp=
We can define classes with attributes/properties as we do in typescript.
==Example from Copilot==
This was the approach spat out by copilot
<syntaxhighlight lang='lisp'>
;; Define a clas for a dog which has a name and sound
(defclass dog ()
    ((name :initarg :name :accessor name)
    (sound :initarg :sound :accessor sound))
)
;; Create an instance of the dog class
(defvar *dog* (make-instance 'dog :name "Rover" :sound "Woof"))
;; Get the name of the dog
(format t "Dog name is ~a ~%" (name *dog*))
;; Get the sound of the dog
(format t "Dog sound is ~a ~%" (sound *dog*))
</syntaxhighlight>
==Example from Derek==
Here is the second attempt
<syntaxhighlight lang='lisp'>
;; Define dog class
(defclass dog2 ()
    ((name)
    (sound))
)
;; Use make-instance to create an instance of the dog class
(defvar *dog2* (make-instance 'dog2))
;; Set the name of the dog
(setf (slot-value *dog2* 'name) "Rover")
;; Set the sound of the dog
(setf (slot-value *dog2* 'sound) "Woof")
;; Get the name of the dog
(format t "Dog name is ~a ~%" (slot-value *dog2* 'name))
;; Get the sound of the dog
(format t "Dog sound is ~a ~%" (slot-value *dog2* 'sound))
</syntaxhighlight>
I did some homework, but sir!!!!, and it said
==Example 3 with hello vera==
This is another example with some options
<syntaxhighlight lang='lisp'>
;; This time we have
;; an accessor name different value dog-name
;; default sound of woof
;; food we will be write only accessor
;; home will be read only accessor
(defclass dog3 ()
    (
      (name 
        :initarg :name  :accessor dog-name)
      (sound
        :initarg :sound :accessor dog-sound :initform "woof" )
      (food
        :initarg :sound :reader get-food :initform "bounce" )
    )
)
;; Create an instance of the dog3 class
(defvar *dog3* (make-instance 'dog3 :name "Rover"))
;; Get the name of the dog
(format t "Dog name is ~a ~%" (dog-name *dog3*))
(format t "Dog sound is ~a ~%" (dog-sound *dog3*))
(format t "Dog food is ~a ~%" (get-food *dog3*))
</syntaxhighlight>
==Adding Methods==
Methods do not belong to classes in lisp. Instead they belong to generic functions. Let create one which take a parameter
<syntaxhighlight lang='lisp'>
;; Let define a generic function for dog3
(defgeneric show-properties (dog))
;; Define a method for generic function to show properties of dog3
(defmethod show-properties ((dog dog3))
    (format t "Property name is ~a ~%" (slot-value dog 'name))
    (format t "Property sound is ~a ~%" (slot-value dog 'sound))
)
(format t "---------------- ~%")
;; Use show-properties to show the properties of dog3
(show-properties *dog3*)
</syntaxhighlight>
This outputs
<syntaxhighlight lang='txt'>
----------------
Property name is Rover
Property sound is woof
</syntaxhighlight>
==Subclass a Class==
We can do this too
<syntaxhighlight lang='lisp'>
;; To define a subclass of dog3
(defclass dog4 (dog3)
    (
      (breed
        :initarg :breed  :accessor dog-breed)
    )
)
;; Create an instance of dog4
(defvar *dog4* (make-instance 'dog4 :name "Rover2" :breed "Labrador"))
;; Use the method show-properties to show the properties of dog4
;; Not no breed is shown
(show-properties *dog4*)
</syntaxhighlight>
This outputs
<syntaxhighlight lang='txt'>
----------------
Property name is Rover2
Property sound is woof
</syntaxhighlight>
=Data Structures=
==Arrays==
===Simple Array===
We do this like so
<syntaxhighlight lang='lisp'>
;; Define an array on names
(defvar *names* (make-array 5 :initial-element "Fred"))
;; Set the first element of the array
(setf (aref *names* 0) "Fred")
;; Set the second element of the array
(setf (aref *names* 1) "Fred2")
</syntaxhighlight>
===3D Array===
We can do 3-dimensional arrays too
<syntaxhighlight lang='lisp'>
;; Make a 3x3 number array
(defvar *numbers* (make-array '(3 3)
  :initial-contents '((0 1 2) (3 4 5) (6 7 8))))
;; Print the array with dotimes
(dotimes (i 3)
    (dotimes (j 3)
        (format t "Number is ~d ~%" (aref *numbers* i j))
    )
)
</syntaxhighlight>
==Hashtables==
Getting into this as they start talking my language. Here is creation and remove of hash table
<syntaxhighlight lang='lisp'>
;; Make a hash table
(defvar *my-hash* (make-hash-table))
;; Set the value of the hash table
(setf (gethash '101 *my-hash*) "Fred 101")
(setf (gethash '102 *my-hash*) "Fred 102")
(setf (gethash '103 *my-hash*) "Fred 103")
;; Get the value of the hash table
(format t "Hash value is ~a ~%" (gethash '101 *my-hash*))
;; Using maphash and lambda format the hash table
(maphash #'(lambda (key value)
    (format t "Key is ~a Value is ~a ~%" key value)
) *my-hash*)
;; Delete a key from the hash table
(remhash '101 *my-hash*)
</syntaxhighlight>
==Structures==
We can create custom structure to store our data
<syntaxhighlight lang='lisp'>
;; Create a custom structure
(defstruct person
    name
    age
    id)
;; Create an instance of the person structure
(defvar *person* (make-person :name "Fred" :age 21 :id 101))
;; Get the name of the person
(format t "Person name is ~a ~%" (person-name *person*))
;; Change the id of the person
(setf (person-id *person*) 102)
</syntaxhighlight>
=File-IO=
And Finally Esther, And finally Cyril. We are able to read and write files with lisp
==Writing a File==
<syntaxhighlight lang='lisp'>
;; An example of writing new data to a file checking if it exists
(defun write-to-file (filename data)
    (with-open-file (stream filename
        :direction :output
        :if-exists :supersede)
        (princ data stream))
)
;; Write some data to a file
(write-to-file "test.txt" "Hello World")
</syntaxhighlight>
==Writing a File==
<syntaxhighlight lang='lisp'>
;; An example of reading data from a file that exists
(defun read-from-file (filename)
    (with-open-file (stream filename)
        (let ((data (read-line stream)))
            (format t "Data is ~a ~%" data)
            data))
)
;; Read some data from a file
(read-from-file "test.txt")
</syntaxhighlight>
=Schema=
The seems to be a battle even longer than the curly bracket between lisp people. So I have found something call schema from mit which has led me back to why I was looking at this - continuation. It took me a while (which I do not think it should do) to do
<syntaxhighlight lang="bash">
echo | mit-scheme --load test.sch
</syntaxhighlight>
So to demonstrate the call/cc (which is not available in common lisp we have
<syntaxhighlight lang="scm">
(let (
  (my-val (call/cc
            (lambda (the-continuation)
              (display "This will be executed\n")
              (the-continuation 5)
              (display "Hello 2 not executed \n") ) ) ) )
  (display my-val) )
</syntaxhighlight>
This seems to amount to early return which seems a lot of noise about nothing. We shall see.
=Special Forms=
Here is a list of special forms and where used some detail
{|class="wikitable"
|block
|let*
|[[#return-from|return-from]] 
|-
|catch
|load-time-value
|[[#setq|setq]] 
|-
|eval-when
|locally
|symbol-macrolet 
|-
|[[#flet|flet]]
|macrolet
|tagbody         
|-
|function
|multiple-value-call
|the
|-
|go
|multiple-value-prog1
|throw         
|-
|[[#if|if]] 
|[[#progn|progn]] 
|unwind-protect 
|-
|[[#labels|labels]] 
|progv                                 
|-
|let
|[[#quote|quote]] 
|}
==quote==
Quote is a special form which stops the lisp interpreter. So the thing is a value (number, symbol, string) rather than a variable in a function<br>
<br>
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 ()
<syntaxhighlight lang="lisp">
(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)
</syntaxhighlight>
==setq==
This appears to be identical to setf i.e. (setq x y) is exactly equivalent to (setf x y). Maybe legacy?
<syntaxhighlight lang="lisp">
(defvar *test-data* "Fred") 
(format t "default ~a ~%" *test-data*)
(setq *test-data* "Fredq")
(format t "setq ~a ~%" *test-data*)
(setf *test-data* "Fredf")
(format t "setf ~a ~%" *test-data*)
</syntaxhighlight>
==return-from==
By default the return value is the last statement executed. To override this we use the special form return-from and the function name
<syntaxhighlight lang="lisp">
(defun get-average-return (a b)
  (return-from get-average-return (/ (+ a b) 2)))
</syntaxhighlight>
==if==
With lisp the if statement has two lines by default to implement the else. For not we add an not operator
<syntaxhighlight lang="lisp">
;; 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 ~%"))
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 11:56, 10 September 2024

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

Useful Links

Not gonna type forever whilst someone else already has. I remember by typing but here is a more professional approach Lisp Works

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

I have a lot of trouble reading the manuals for anything. YouTube has been a god send for me along with examples. If there are youtuber out there please make a video on how to read the manual. Probably all me but this is written in greek to me. I probably give up too easily

flet ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*

Comments

;;;; Describe Program 4 semi colons
;;; Comments

;; Indented Comments

#|| Multiline
My Comments
||#

Format to terminal

(format t "Hello World ~%")

Print

(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)))

Splicing

Not sure my odds of remembering. The @ after a comma within quote - yes I know, then the form following the at-sign is evaluated to produce a list of objects

;; Create a list
(defvar *my-list* (list 0 1 2 3 4 5))

;; a reminder of rest which mean everything but the first like javascript
(format t "List with rest is ~a ~%" (rest *my-list*))

;; Splice a list

;; List with 0 is (0 1 2 3 4 5) 
(format t "List with 0 is ~a ~%" `(0 ,@(rest *my-list*)))

;; List with 2 is (2 1 2 3 4 5) 
(format t "List with 2 is ~a ~%" `(2 ,@(rest *my-list*)))

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

For if statements Special Forms

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 ~%")))

Fun with Cars

car

So for car this is simple

(defvar *my-list* (list 0 1 2 3 4 5))
; Returns first element in list i.e. 0
(format t "First element is ~a ~%" (car *my-list*))

cdr (pronounced cudder)

So for cdr is just the rest

(defvar *my-list* (list 0 1 2 3 4 5))
; Returns rest of the elements in list i.e. 1 2 3 4 5
(format t "First element is ~a ~%" (cdr *my-list*))

All the combinations

Found a page which seems to explain the unexplainable. To understand the terms now we need to understand

This place ... Is equivalent to this place ...
(caar x) (car (car x))
(cadr x) (car (cdr x))
(cdar x) (cdr (car x))
(cddr x) (cdr (cdr x))
(caaar x) (car (car (car x)))
(caadr x) (car (car (cdr x)))
(cadar x) (car (cdr (car x)))
(caddr x) (car (cdr (cdr x)))
(cdaar x) (cdr (car (car x)))
(cdadr x) (cdr (car (cdr x)))
(cddar x) (cdr (cdr (car x)))
(cdddr x) (cdr (cdr (cdr x)))
(caaaar x) (car (car (car (car x))))
(caaadr x) (car (car (car (cdr x))))
(caadar x) (car (car (cdr (car x))))
(caaddr x) (car (car (cdr (cdr x))))
(cadaar x) (car (cdr (car (car x))))
(cadadr x) (car (cdr (car (cdr x))))
(caddar x) (car (cdr (cdr (car x))))
(cadddr x) (car (cdr (cdr (cdr x))))
(cdaaar x) (cdr (car (car (car x))))
(cdaadr x) (cdr (car (car (cdr x))))
(cdadar x) (cdr (car (cdr (car x))))
(cdaddr x) (cdr (car (cdr (cdr x))))
(cddaar x) (cdr (cdr (car (car x))))
(cddadr x) (cdr (cdr (car (cdr x))))
(cdddar x) (cdr (cdr (cdr (car x))))
(cddddr x) (cdr (cdr (cdr (cdr x))))

Functions 3

A while ago we did lists and they had this insane thing called caar, cadar, cddar as Car of Car and gets the car of car or the first item in the list

  • caar is (car (car x))
  • cadar is (car (cdr (car x)))
  • cddar is (cdr (cdr (car x)))

caar

(car (car x))
From inside to outside
First item = (superman (6 ft 3 in) ( 230 lbs))
And first item of this = superman

cadar

(car (cdr (car x)))
From inside to outside
First item = (superman (6 ft 3 in) ( 230 lbs))
rest of items = (6 ft 3 in) ( 230 lbs))
first item (6 ft 3 in)

cddar

(cdr (cdr (car x)))
From inside to outside
First item = (superman (6 ft 3 in) ( 230 lbs))
rest of items = (6 ft 3 in) ( 230 lbs))
rest of items = ( 230 lbs))

(defparameter *my-heroes* `( (superman (6 ft 3 in) ( 230 lbs))
                             (batman  (6 ft 0 in) ( 190 lbs))
                             (spiderman (6 ft 2 in) ( 210 lbs))))

(defun get-heroes-data (size) 
    (format t "Heroes ~a ~%" 
        `(,(caar size) is ,(cadar size), (cddar size))))

; Heroes (cdr (cdr (car x)))(Superman Is (6 Ft 3 In) ((230 Lbs)))
(get-heroes-data *my-heroes*)

Mapping over a list

Here we map over a function, in this case numberp

;; mapcar example of using a function
;; mapcar List is (T T T Nil Nil)
(format t "mapcar List is ~a ~%" (mapcar #'numberp  `(1 2 3 g d)))

Lambda

Lambda is a way of defining an anonymous function in lisp. We can pass functions to mapcar using the hash quote e.g. #`

; mapcar List is (3 6 9 12 15)
(format t "mapcar List is ~a ~%" (mapcar #'(lambda (x) (* 3 x)) '(1 2 3 4 5)))


Got confused with this because on the use of print

(mapcar #'(lambda (x) (print (* 3 x))) '(1 2 3 4 5))

Guess this the equivalent of

[1, 2, 3, 4, 5].map((n)=> console.log(n))

And

// mapcar List is [1, 2, 3, 4, 5]
console.log('mapcar List is %o',  [1, 2, 3, 4, 5].map((n)=> n))

multiple-value-bind

Not too sure what a macro is, but that is what this is. I suspect it is a way of extending existing functionality. This is an example of calling a function which returns two values. To do this we use the accessor values

(defun expose-me (num)
    (values (expt num 2) (expt num 3)))

;; Example of multiple value call
(multiple-value-bind (arg-a arg-b) (expose-me 2)
    (format t "2^2 = ~d 2^3 = ~d~%" arg-a arg-b))

Macros

Example 1

This is taken from geeksforgeeks and does seem easy to understand however here is the quote from another page. A macro is an ordinary piece of Lisp code that operates on another piece of putative Lisp code, translating it into (a version closer to) executable Lisp.

(defmacro sumup (a b) 
    ; This line will be executed whenever 
      ; we use the macro sum 
    ; with two integer parameters 
    (format t "~D + ~D : ~D" a b (+ a b)) 
) 
; Calling macro sumup with parameters 7 and 18 
(sumup 7 18) 
(terpri)

So done with all that and my good friend Derek Banas sorts the Greek out for me. He explained that a common problem my be that you have to often have multiple lines in an if statement and it can be annoying to use progn all of the time to do this. (When I think of C and macro usage in it, it smacks of the same problem.

Here is an example of the problem not the example

(defvar *num* 2)
(defvar *num-2* 0)

(if (= *num* 2)
    (progn 
      (setf *num-2* 3)
      (format t "num-2 is ~d ~%" *num-2*)
    )
    (format t "Not equal to 2 ~%"))

So with macros we need to have it generate code not be code like we do in C

(defmacro ifit (condition &rest body)
    `(if ,condition
        (progn
            ,@body)
        (format t "Can't Drive ~%"))
)

(setf *age* 18)

(ifit (>= *age* 18)
    (format t "Line one of lisp ~%")
    (format t "Line two of Lisp ~%")
    (format t "Line three of Lisp ~%")
    (terpri)
)

In the macro we use quasi quoting which is where we switch between code and data using the comma for expression and ,@ for the multiple lines. This replacing the condition and body with the quoted value not the evaluated value.

Example 2

I am not feeling the love with second example. I will have to use some of this to appreciate it I think. It is just like C I think so just a way to generate repetitive code where the language is to granular.

;; Function to add two numbers
(defun add (a b) 
    (let ((sum (+ a b))) 
        (format t "Sum of ~d and ~d is ~d ~%" a b sum) 
        sum) 
)

;; Create a macro to add two numbers
(defmacro letx (var val &rest body) 
    `(let ((,var ,val)) 
        ,@body)
)

;; define a function to use letx
(defun addx (a b) 
    (letx sum (+ a b) 
        (format t "Sum of ~d and ~d is ~d ~%" a b sum) 
        sum) 
)

;; Call the function
(addx 2 3)

Classes In Lisp

We can define classes with attributes/properties as we do in typescript.

Example from Copilot

This was the approach spat out by copilot

;; Define a clas for a dog which has a name and sound
(defclass dog ()
    ((name :initarg :name :accessor name)
    (sound :initarg :sound :accessor sound))
)

;; Create an instance of the dog class
(defvar *dog* (make-instance 'dog :name "Rover" :sound "Woof"))

;; Get the name of the dog
(format t "Dog name is ~a ~%" (name *dog*))
;; Get the sound of the dog
(format t "Dog sound is ~a ~%" (sound *dog*))

Example from Derek

Here is the second attempt

;; Define dog class
(defclass dog2 ()
    ((name)
    (sound))
)

;; Use make-instance to create an instance of the dog class
(defvar *dog2* (make-instance 'dog2))

;; Set the name of the dog
(setf (slot-value *dog2* 'name) "Rover")
;; Set the sound of the dog
(setf (slot-value *dog2* 'sound) "Woof")

;; Get the name of the dog
(format t "Dog name is ~a ~%" (slot-value *dog2* 'name))
;; Get the sound of the dog
(format t "Dog sound is ~a ~%" (slot-value *dog2* 'sound))

I did some homework, but sir!!!!, and it said

Example 3 with hello vera

This is another example with some options

;; This time we have 
;; an accessor name different value dog-name
;; default sound of woof
;; food we will be write only accessor
;; home will be read only accessor
(defclass dog3 ()
    (
      (name  
        :initarg :name  :accessor dog-name)
      (sound 
        :initarg :sound :accessor dog-sound :initform "woof" )
      (food 
        :initarg :sound :reader get-food :initform "bounce" )
    )
)

;; Create an instance of the dog3 class
(defvar *dog3* (make-instance 'dog3 :name "Rover"))

;; Get the name of the dog
(format t "Dog name is ~a ~%" (dog-name *dog3*))
(format t "Dog sound is ~a ~%" (dog-sound *dog3*))
(format t "Dog food is ~a ~%" (get-food *dog3*))

Adding Methods

Methods do not belong to classes in lisp. Instead they belong to generic functions. Let create one which take a parameter

;; Let define a generic function for dog3
(defgeneric show-properties (dog))

;; Define a method for generic function to show properties of dog3
(defmethod show-properties ((dog dog3))
    (format t "Property name is ~a ~%" (slot-value dog 'name))
    (format t "Property sound is ~a ~%" (slot-value dog 'sound))
)

(format t "---------------- ~%")

;; Use show-properties to show the properties of dog3
(show-properties *dog3*)

This outputs

---------------- 
Property name is Rover 
Property sound is woof

Subclass a Class

We can do this too

;; To define a subclass of dog3
(defclass dog4 (dog3)
    (
      (breed 
        :initarg :breed  :accessor dog-breed)
    )
)

;; Create an instance of dog4
(defvar *dog4* (make-instance 'dog4 :name "Rover2" :breed "Labrador"))

;; Use the method show-properties to show the properties of dog4
;; Not no breed is shown
(show-properties *dog4*)

This outputs

---------------- 
Property name is Rover2
Property sound is woof

Data Structures

Arrays

Simple Array

We do this like so

;; Define an array on names
(defvar *names* (make-array 5 :initial-element "Fred"))

;; Set the first element of the array
(setf (aref *names* 0) "Fred")
;; Set the second element of the array
(setf (aref *names* 1) "Fred2")

3D Array

We can do 3-dimensional arrays too

;; Make a 3x3 number array
(defvar *numbers* (make-array '(3 3)
  :initial-contents '((0 1 2) (3 4 5) (6 7 8))))

;; Print the array with dotimes
(dotimes (i 3)
    (dotimes (j 3)
        (format t "Number is ~d ~%" (aref *numbers* i j))
    )
)

Hashtables

Getting into this as they start talking my language. Here is creation and remove of hash table

;; Make a hash table
(defvar *my-hash* (make-hash-table))

;; Set the value of the hash table
(setf (gethash '101 *my-hash*) "Fred 101")
(setf (gethash '102 *my-hash*) "Fred 102")
(setf (gethash '103 *my-hash*) "Fred 103")
;; Get the value of the hash table
(format t "Hash value is ~a ~%" (gethash '101 *my-hash*))
;; Using maphash and lambda format the hash table
(maphash #'(lambda (key value)
    (format t "Key is ~a Value is ~a ~%" key value)
) *my-hash*)

;; Delete a key from the hash table
(remhash '101 *my-hash*)

Structures

We can create custom structure to store our data

;; Create a custom structure
(defstruct person
    name
    age
    id)

;; Create an instance of the person structure
(defvar *person* (make-person :name "Fred" :age 21 :id 101))

;; Get the name of the person
(format t "Person name is ~a ~%" (person-name *person*))

;; Change the id of the person
(setf (person-id *person*) 102)

File-IO

And Finally Esther, And finally Cyril. We are able to read and write files with lisp

Writing a File

;; An example of writing new data to a file checking if it exists
(defun write-to-file (filename data)
    (with-open-file (stream filename
        :direction :output
        :if-exists :supersede)
        (princ data stream))
)

;; Write some data to a file
(write-to-file "test.txt" "Hello World")

Writing a File

;; An example of reading data from a file that exists
(defun read-from-file (filename)
    (with-open-file (stream filename)
        (let ((data (read-line stream)))
            (format t "Data is ~a ~%" data)
            data))
)

;; Read some data from a file
(read-from-file "test.txt")

Schema

The seems to be a battle even longer than the curly bracket between lisp people. So I have found something call schema from mit which has led me back to why I was looking at this - continuation. It took me a while (which I do not think it should do) to do

echo | mit-scheme --load test.sch

So to demonstrate the call/cc (which is not available in common lisp we have

(let (
  (my-val (call/cc
            (lambda (the-continuation)
              (display "This will be executed\n")
              (the-continuation 5)
              (display "Hello 2 not executed \n") ) ) ) )
  (display my-val) )

This seems to amount to early return which seems a lot of noise about nothing. We shall see.

Special Forms

Here is a list of special forms and where used some detail

block let* return-from
catch load-time-value setq
eval-when locally symbol-macrolet
flet macrolet tagbody
function multiple-value-call the
go multiple-value-prog1 throw
if progn unwind-protect
labels progv
let quote

quote

Quote is a special form which stops the lisp interpreter. So the thing is a value (number, symbol, string) rather than a variable in a function

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)

setq

This appears to be identical to setf i.e. (setq x y) is exactly equivalent to (setf x y). Maybe legacy?

(defvar *test-data* "Fred")  
(format t "default ~a ~%" *test-data*)
(setq *test-data* "Fredq")
(format t "setq ~a ~%" *test-data*)
(setf *test-data* "Fredf")
(format t "setf ~a ~%" *test-data*)

return-from

By default the return value is the last statement executed. To override this we use the special form return-from and the function name

(defun get-average-return (a b)
  (return-from get-average-return (/ (+ a b) 2)))

if

With lisp the if statement has two lines by default to implement the else. For not we add an not operator

;; 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 ~%"))