Skip to content

Commit

Permalink
Reading progress at Chapter 9 of Land of Lisp
Browse files Browse the repository at this point in the history
That chapter talks about the built-in advanced datatypes of Common Lisp like
arrays, strings, structures and hash-tables.
Actually any type instead of list or symbols.

Between the examples is commented as well about multiple-values return,
like the bridge between (values) and (multiple-value-bind).

The final of Chapter is reserved of a special type game called Orc Battle using
the concepts of this section, given a notorious attention to the usage of
generic programming and the simple object-oriented system: defstruct + defmethod

Well... after more than week doing nothing more than nothing, at least this
is some progress on that reading.

I wish finish that book until the new semester begin.
  • Loading branch information
ryukinix committed Feb 18, 2017
1 parent c15e661 commit 11a1e12
Show file tree
Hide file tree
Showing 2 changed files with 302 additions and 3 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
A personal repository for annotation about learning lisp patterns.
The actual content are answers and code covering the book [Land of Lisp](http://www.landoflisp.com) and the insights at the MIT 6.001 Course about Structures and Interpretations of Computer Programs.

# Land of Lisp book (reading) [154/482]
![progress](http://progressed.io/bar/31)
# Land of Lisp book (reading) [172/482]
![progress](http://progressed.io/bar/35)

- [x] Chapter 1 (intro)
- [x] Chapter 2 (guess my numbers)
Expand All @@ -14,7 +14,7 @@ The actual content are answers and code covering the book [Land of Lisp](http://
- [x] Chapter 6.5 (lambda chapter)
- [x] Chapter 7 (go beyond basic lists)
- [x] Chapter 8 (grand theft wumpus)
- [ ] Chapter 9
- [ ] Chapter 9 (advanced datatypes and generic programming)
- [ ] Chapter 10
- [ ] Chapter 11
- [ ] Chapter 12
Expand Down
299 changes: 299 additions & 0 deletions land-of-lisp/cap9-advanced-generic-programming.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
;; Common Lisp Script
;; Manoel Vilela

;; advanced datatypes:
;; + ARRAY
;; + HASH-TABLES
;; + STRINGS
;; + STRUCTURES

;; generic functions:
;; sequence functions:
;; + REDUCE
;; + FIND-IF
;; + SOME
;; + EVERY
;; + POSITION
;; + COUNT
;; generic setter:
;; + SETF

;; best way to handle various datatypes: DEFMETHOD

(defparameter examples nil)

(defmacro define-example (name &rest body)
`(push (cons (quote ,name)
(apply #'list (quote ,body))) examples))

(define-example example-of-arrays
(make-array 3)
;; => #(0 0 0)
(defparameter x (make-array 3))
;; x => #(0 0 0)
(aref x 1) ;; => 0

;; the generic setf macro operator
(setf (aref x 1) 'foo)
;; x => #(0 FOO 0)
;; combining setf + aref we can set elements on
;; array positions

;; but this can be used in list too!
;; yes... lists of common lisp is not immutable!
;; functional programming? forget about that.

(defparameter foo '(a b c))
foo
;; foo => (a b c)
(second foo)
;; => B
(setf (second foo) 'z)
foo
;; => (a z c)

;; setf is a magic setter.
(defparameter foo (make-array 4))
foo
;; => #(0 0 0 0)

(setf (aref foo 2) '(x y z))
foo
;; => #(0 0 (X Y Z) 0)

(setf (car (aref foo 2)) (make-hash-table))
;; hash tables has its own examples in the next section

(setf (gethash 'zoink (car (aref foo 2))) 5)
foo
;; => #(0 0 (#<HASH-TABLE :TEST EQL :COUNT 1 {100382B253}> Y Z) 0)
)

(define-example array-vs-lists
(nth 1 '(foo bar baz))
;; access O(n)

(aref #(foo bar baz) 1)
;; access O(1)

;; tl;dr => array has a better performance than lists

)


;; hash tables are like alists (assoc lists) => ((key value) ... ... ... (key-n value-n))
(define-example example-of-hash-tables
;; create a new hash table
(make-hash-table)
;; => #<HASH-TABLE :TEST EQL :COUNT 0 {10049714B3}>
(defparameter x (make-hash-table))
(gethash 'yup x)
;; => NIL, NIL
(setf (gethash 'yup x) '25)
(gethash 'yup x)
;; => 25, T

;; defining drink-order example like alist made before
(defparameter *drink-order* (make-hash-table))
(setf (gethash 'bill *drink-order*) 'double-espresso)
(setf (gethash 'lisa *drink-order*) 'small-drip-coffee)
(setf (gethash 'john *drink-order*) 'medium-latte)

;; accessing the drink order for any person
(gethash 'lisa *drink-order*)
;; hash table access performance is like array
;; access/set time -> O(1)
)

(define-example returning-multiple-values
(round 2.4)
;; => 2, 0.4
(defun foo () (values 3 7))
(foo)
;; => 3, 7
(+ (foo) 5)
;; => 8 (ignoring the second value)

;; bind multiple values from functions and create
;; a lexical scope like let
(multiple-value-bind (a b) (foo)
(+ a b))
;; => 10

;; the usage of multiple-values is supported by CL
;; but is not so common used on moderns lisp dialects
;; like clojure

;; BTW, Land of Lisp explicitly say that on this book
;; we don't will see much examples of this.

;; I don't have sure if this is really useful.
;; Maybe passing error state like Go (value error)
)

(define-example example-of-structures
(defstruct person
:name
:age
:waist-size
:favorite-color) ;; 4 slots
(defparameter *bob* (make-person :name "Bob"
:age 35
:waist-size 32
:favorite-color "blue"))
*bob*
;; => #S(PERSON :NAME "Bob" :AGE 35 :WAIST-SIZE 32 :FAVORITE-COLOR "blue")
(person-age *bob*)
;; => 35
(setf (person-age *bob*) 36) ;; the magic setter macro again
;; works fine with structures as well
(person-age *bob*)
;; => 36


;; the problem of lispers and object-oriented programming
;; let's see a alternative for structures only using lists
(defun make-person. (name age waist-size favorite-color)
(list name age waist-size favorite-color))
(defun person-age. (person)
(cadr person))
(defparameter *bob* (make-person. "bob" 35 32 "blue"))
*bob*
(person-age. *bob*)

;; but is a bad idea. we'll need all the selectors for person
;; and the REPL representation is useless. How we can say if
;; this list define a person. Bob's age is 35 or 32?
;; Another problem is changing the state... lists don't works well
;; with it. First: your nature is a bunch of recursive cons cells.
;; In that example the better approach is defining structures in CL.

)


(define-example example-handling-data-in-a-generic-way
;; a great example of generic function
;; at which can handle various types is the
;; function length
;; that type of functions are called of:
;; "sequence functions" (handle sequences)
(length "blub")
;; => 4
(length '(a b c))
;; => 3
(length (make-array 5))
;; => 5

;; another great examples for sequence functions
;; are the specific for search:
;; find-if, count, position, some and every

(find-if #'numberp '(a b 5 d))
;; => 5
(count #\s "Mississippi")
;; => 4
(position #\4 "2kewl4skewl")
;; => 5
(some #'numberp '(a b 5 d))
;; => T
(every #'numberp '(a b 5 d))
;; => NIL

;; another useful generic sequence function: reduce
(reduce #'+ '(3 4 6 5 2))
;; => 20
;; an way to understand the evaluation of reduce is
(reduce #'cons '(1 2 3 4))
;; => (((1 . 2) . 3) . 4)
(reduce (lambda (best item)
(if (and (evenp item)
(> item best))
item
best))
'(7 4 6 5 2)
:initial-value 0)
;; => 6
;; without define the initial-value we got 7


(defun sum (sequence)
(reduce #'+ sequence))

(sum '(1 2 3))
(sum #(1 2 3 4 5))

(map 'string
(lambda (x)
(if (eq x #\s)
#\S
x))
"this is a string")

;; two more import sequence functions: subseq and
;; sort

(subseq "america" 2 6)
;; => eric
(sort '(5 8 2 4 9 3 6) #'<)
;; => (2 3 4 5 6 8 9)

;; we can create our own generic functions
;; using typing checking; the most frequently
;; predicates are: arrayp, characterp, consp,
;; hash-table-p, listp, stringp, symbolp

(defun add (a b)
(cond ((and (numberp a)
(numberp b))
(+ a b))
((and (listp a)
(listp b))
(append a b))))

(add 1 2)
;; => 3
(add '(1 2) '(3 4))
;; => (1 2 3 4)

;; but we have a better way to do this using
;; generic methods for multiple types
;; this is called "type dispatching"

(defmethod add. ((a number) (b number))
(+ a b))

(defmethod add. ((a list) (b list))
(append a b))

(add. 1 2)
(add. '(a b) '(c d))


;; the `defmethod` is like `defun` except that it
;; allows us to write multiple functions with
;; the same name

;; defstruct + defmethod => simple OO system
)


(defun print-example (example)
(let ((name (car example))
(instrunctions (cdr example)))
(format t ":: ~A ~%" name)
(loop for i in instrunctions do
(format t "> ~a~%~a~%" i (eval i)))
(princ #\newline)))

(defun run-examples ()
(mapcar #'print-example (reverse examples)))


;; the continuation of this chapter is a game called:
;; ORC BATTLE GAME
;; I'll write the functions in another file because
;; this is especial of only REPL examples at which
;; I use the define-example macro to can be executable


(run-examples)

0 comments on commit 11a1e12

Please sign in to comment.