Lisp

From bibbleWiki
Revision as of 05:18, 7 September 2024 by Iwiseman (talk | contribs) (cond)
Jump to navigation Jump to search

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

(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

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

Functions 3

A while ago we did lists and they had this insane thing called caar, cadar, cddar

  • caar is known as Car of Car and gets the car of car or the first item in the list
  • cadar is known as
(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))))

(get-heroes-data *my-heroes*)