├── .gitignore ├── LICENSE ├── README.md ├── land-of-lisp ├── cap10-life-simulation.lisp ├── cap10-loop.lisp ├── cap11-attack-of-the-robots.lisp ├── cap11-format.lisp ├── cap12-socket-client.lisp ├── cap12-socket-server.lisp ├── cap12-streams.lisp ├── cap13-error-handling.lisp ├── cap13-webserver.lisp ├── cap14-functional-programming.lisp ├── cap15-dice-of-doom.lisp ├── cap16-magic-with-macros.lisp ├── cap17-domain-specific-languages.lisp ├── cap17-text-game-adventure-v2.lisp ├── cap18-dice-of-doom-v2.lisp ├── cap18-lazy-programming.lisp ├── cap19-web-dice-of-doom-v3.lisp ├── cap2-guess-my-number.lisp ├── cap20-dice-of-doom-v4.lisp ├── cap4-conditionals.lisp ├── cap5-building-a-text-game-engine.lisp ├── cap6-reading-and-printing.lisp ├── cap6.5-lambda.lisp ├── cap7-beyond-basic-lists.lisp ├── cap8-neowumpus.lisp ├── cap9-advanced-generic-programming.lisp ├── cap9-orc-battle-game.lisp ├── city.png ├── example.svg ├── known-city.png ├── random_walk.svg ├── wizard-graph-undirected.dot.png └── wizard-graph.dot.png ├── mit-6.001 ├── 10A-compilation.lisp ├── 10B-storage-allocation-and-garbage-collector.lisp ├── 1A-heuristic-square-root.lisp ├── 1B-iterative-vs-recursive.lisp ├── 2A-lambda-expressions.lisp ├── 2B-compund-data.lisp ├── 3A-data-abstraction.lisp ├── 3B-symbolic-differentiation.lisp ├── 4A-pattern-matching.lisp ├── 4B-generic-operators.lisp ├── 5A-state-and-side-effects.lisp ├── 5B-computational-objects.lisp ├── 6A-streams-I.lisp ├── 6B-streams-II.lisp ├── 7A-metacircular-evaluator-I.lisp ├── 7B-metacircular-evaluator-II.lisp ├── 8A-logic-programming-I.lisp ├── 8B-logic-programming-II.lisp ├── 9A-register-machines.lisp └── 9B-explicit-control-evaluator.lisp └── random ├── command-line-args.lisp ├── compose.lisp ├── game-of-life-sdl.lisp └── namespaces-troll.lisp /.gitignore: -------------------------------------------------------------------------------- 1 | *.FASL 2 | *.fasl 3 | *.lisp-temp 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Manoel Vilela 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lisp-insights 2 | A personal repository for annotation about learning lisp patterns. 3 | The current content are answers plus code covering of the book [Land of Lisp](http://www.landoflisp.com) and the insights at the MIT 6.001 Course: Structures and Interpretations of Computer Programs. 4 | 5 | 6 | # Land of Lisp book (reading) [482/482] 7 | 8 | - [x] Section I: Lisp is Power 9 | - [x] Chapter 1 (intro) 10 | - [x] Chapter 2 (guess my numbers) 11 | - [x] Chapter 3 (exploring syntax of lisp) 12 | - [x] Section II: Lisp is Symmetry 13 | - [x] Chapter 4 (conditionals) 14 | - [x] Chapter 5 (building a text game engine) 15 | - [x] Chapter 6 (printing files) 16 | - [x] Chapter 6.5 (lambda chapter) 17 | - [x] Chapter 7 (go beyond basic lists) 18 | - [x] Chapter 8 (grand theft wumpus) 19 | - [x] Chapter 9 (advanced datatypes and generic programming) 20 | - [x] Section III: Lisp is Hacking 21 | - [x] Chapter 10 (looping with the loop command) 22 | - [x] Chapter 11 (printing with the format function) 23 | - [x] Chapter 12 (working with streams) 24 | - [x] Chapter 13 (let's create a web server -- agh :<) 25 | - [x] Section IV: Lisp is Science 26 | - [x] Chapter 14 (Ramping lisp up a Notch with Functional Programming) 27 | - [x] Chapter 15 (Dice of Doom, a Game Written in the Functional Style) 28 | - [x] Chapter 16 (The Magic of Lisp Macros) 29 | - [x] Chapter 17 (Domain-Specific Languages) 30 | - [x] Chapter 18 (Lazy Programming) 31 | - [x] Chapter 19 (Creating a Graphical, Web-Based Version of Dice of Doom) 32 | - [x] Chapter 20 (Making Dice of Doom More Fun) 33 | - [x] Epilogue (the lisp dialects and lisp techniques) 34 | 35 | 36 | # [MIT 6.001 Structures and Interpretations of Computer Programs](https://www.youtube.com/watch?v=2Op3QLzMgSY&list=PLE18841CABEA24090) 37 | 38 | - [x] Lecture 1A 39 | - [x] Lecture 1B 40 | - [x] Lecture 2A 41 | - [x] Lecture 2B 42 | - [x] Lecture 3A 43 | - [x] Lecture 3B 44 | - [x] Lecture 4A 45 | - [x] Lecture 4B 46 | - [x] Lecture 5A 47 | - [x] Lecture 5B 48 | - [x] Lecture 6A 49 | - [x] Lecture 6B 50 | - [x] Lecture 7A 51 | - [x] Lecture 7B 52 | - [x] Lecture 8A 53 | - [x] Lecture 8B 54 | - [x] Lecture 9A 55 | - [x] Lecture 9B 56 | - [x] Lecture 10A 57 | - [x] Lecture 10B 58 | -------------------------------------------------------------------------------- /land-of-lisp/cap10-life-simulation.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defparameter *width* 100) 5 | (defparameter *height* 30) 6 | (defparameter *jungle* '(45 10 10 10)) 7 | (defparameter *plant-energy* 80) 8 | (defparameter *reproduction-energy* 200) 9 | 10 | ;; PLANTS WITH (X . Y) KEY COORDINATES HASH-MAP 11 | (defparameter *plants* (make-hash-table :test #'equal)) 12 | ;; need to use #'equal here because the default #'eq 13 | ;; doesn't works fine to compare cons cells. 14 | 15 | 16 | (defun random-plant (left top width height) 17 | (let ((pos (cons (+ left (random width)) 18 | (+ top (random height))))) 19 | (setf (gethash pos *plants*) t))) 20 | 21 | (defun add-plants () 22 | (apply #'random-plant *jungle*) 23 | (random-plant 0 0 *width* *height*)) 24 | 25 | 26 | ;; x y => cartesian location 27 | ;; energy => days left of life 28 | ;; dir => direction as a number between 0 and 7. 29 | ;; 0 1 2 30 | ;; 7 * 3 31 | ;; 6 5 4 32 | ;; genes => list of eight elements 33 | ;; the list of probabilities bounds for decide the daily direction 34 | ;; greater number, more likely to be chosen 35 | (defstruct animal x y energy dir genes) 36 | 37 | 38 | (defparameter *animals* 39 | (list (make-animal :x (ash *width* -1) 40 | :y (ash *height* -1) 41 | :energy 100 42 | :dir 0 43 | :genes (loop repeat 8 44 | collecting (1+ (random 10)))))) 45 | 46 | (defun move (animal) 47 | (let ((dir (animal-dir animal)) 48 | (x (animal-x animal)) 49 | (y (animal-y animal))) 50 | (setf (animal-x animal) (mod (+ x 51 | (cond ((and (>= dir 2) 52 | (< dir 5)) 1) 53 | ((or (= dir 1) 54 | (= dir 5)) 0) 55 | (t -1)) 56 | *width*) 57 | *width*)) 58 | (setf (animal-y animal) (mod (+ y 59 | (cond ((and (>= dir 0) 60 | (< dir 3)) 1) 61 | ((or (>= dir 4) 62 | (< dir 7)) -1) 63 | (t 0)) 64 | *height*) 65 | *height*)) 66 | (decf (animal-energy animal)))) 67 | 68 | (defun turn (animal) 69 | (let ((x (random (apply #'+ (animal-genes animal))))) 70 | (labels ((angle (genes x) 71 | (let ((xnu (- x (car genes)))) 72 | (if (< xnu 0) 73 | 0 74 | (1+ (angle (cdr genes) xnu)))))) 75 | (setf (animal-dir animal) 76 | (mod (+ (animal-dir animal) 77 | (angle (animal-genes animal) x)) 78 | 8))))) 79 | 80 | (defun eat (animal) 81 | (let ((pos (cons (animal-x animal) 82 | (animal-y animal)))) 83 | (when (gethash pos *plants*) 84 | (incf (animal-energy animal) *plant-energy*) 85 | (remhash pos *plants*)))) 86 | 87 | 88 | (defun reproduce (animal) 89 | (let ((e (animal-energy animal))) 90 | (when (>= e *reproduction-energy*) 91 | (setf (animal-energy animal) (ash e -1)) 92 | (let ((animal-nu (copy-structure animal)) 93 | (genes (copy-list (animal-genes animal))) 94 | (mutation (random 8))) 95 | (setf (nth mutation genes) 96 | (max 1 (+ (nth mutation genes) 97 | (random 3) 98 | -1))) 99 | (setf (animal-genes animal-nu) genes) 100 | (push animal-nu *animals*))))) 101 | 102 | (defun update-world () 103 | (setf *animals* (remove-if (lambda (animal) 104 | (<= (animal-energy animal) 0)) 105 | *animals*)) 106 | (mapc (lambda (animal) 107 | (turn animal) 108 | (move animal) 109 | (eat animal) 110 | (reproduce animal)) 111 | *animals*) 112 | (add-plants)) 113 | 114 | (defun draw-world () 115 | (loop for y 116 | below *height* 117 | do (progn (fresh-line) 118 | (princ "|") 119 | (loop for x 120 | below *width* 121 | do (princ (cond ((some (lambda (animal) 122 | (and (= (animal-x animal) x) 123 | (= (animal-y animal) y))) 124 | *animals*) 125 | #\M) 126 | ((gethash (cons x y) *plants*) #\*) 127 | (t #\space)))) 128 | (princ "|")))) 129 | 130 | (defun evolution () 131 | (draw-world) 132 | (fresh-line) 133 | (let ((str (read-line))) 134 | (cond ((equal str "quit") 'nil) 135 | (t (let ((x (parse-integer str :junk-allowed t))) 136 | (if x 137 | (loop for i 138 | below x 139 | do (update-world) 140 | if (zerop (mod i 1000)) 141 | do (princ #\.)) 142 | (update-world)) 143 | (evolution)))))) 144 | 145 | (format t "At each step: 1. type a integer to let evolution for n days, 'quit' for exit and just RETURN to update.. ~%") 146 | (format t "* => PLANT ~%") 147 | (format t "M => ANIMAL ~%") 148 | (evolution) 149 | -------------------------------------------------------------------------------- /land-of-lisp/cap10-loop.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; the loop macro 5 | 6 | (loop for i 7 | below 5 8 | sum i) 9 | ;; => 10 10 | 11 | 12 | ;; counting from a starting point to an ending point 13 | 14 | (loop for i 15 | from 5 16 | to 10 17 | sum i) 18 | ;; => 45 19 | 20 | ;; iterating through values in a list 21 | 22 | (loop for i 23 | in '(100 20 3) 24 | sum i) 25 | ;; => 123 26 | 27 | 28 | ;; doing stuff in a loop 29 | 30 | (loop for i 31 | below 5 32 | do (print i)) 33 | ;; => nil 34 | ;; print 0..5 on stdout 35 | 36 | ;; doing stuff under certain conditions 37 | 38 | (loop for i 39 | below 10 40 | when (oddp i) 41 | sum i) 42 | ;; => 25 43 | 44 | ;; breaking out of a loop early 45 | 46 | (loop for i 47 | from 0 48 | do (print i) 49 | when (= i 5) 50 | return 'falafel) 51 | ;; => 'FALAFEL 52 | ;; printing 0 to 5 on stdout 53 | 54 | ;; collecting a list of values 55 | (loop for i 56 | in '(2 3 4 5 6) 57 | collect (* i i)) 58 | ;; => (4 9 16 25 36) 59 | 60 | 61 | ;; using multiple for clauses 62 | 63 | (loop for x below 10 64 | for y below 10 65 | collect (+ x y)) 66 | ;; => (0 2 4 6 8 10 12 14 16 18) 67 | 68 | ;; nested loop 69 | (loop for x below 10 70 | collect (loop for y below 10 71 | collect (+ x y))) 72 | 73 | ;; => ((0 1 2 3 4 5 6 7 8 9) (1 2 3 4 5 6 7 8 9 10) 74 | ;; (2 3 4 5 6 7 8 9 10 11) (3 4 5 6 7 8 9 10 11 12) 75 | ;; (4 5 6 7 8 9 10 11 12 13) (5 6 7 8 9 10 11 12 13 14) 76 | ;; (6 7 8 9 10 11 12 13 14 15) (7 8 9 10 11 12 13 14 15 16) 77 | ;; (8 9 10 11 12 13 14 15 16 17) (9 10 11 12 13 14 15 16 17 18)) 78 | 79 | (loop for i 80 | from 0 81 | for day 82 | in '(monday tuesday wednesday thursday friday saturday sunday) 83 | collect (cons i day)) 84 | 85 | ;; => ((0 . MONDAY) (1 . TUESDAY) (2 . WEDNESDAY) 86 | ;; (3 . THURSDAY) (4 . FRIDAY) (5 . SATURDAY) (6 . SUNDAY)) 87 | 88 | 89 | ;; Well, this is just the brief introduction to loop macro on Land of Lisp. 90 | ;; The book covers this chapter with this, a periodic table-like for loop 91 | ;; with a lot of examples and on the final a life simulation. I'll cover 92 | ;; that on the next file. See you in soon. 93 | ;; EOF 94 | -------------------------------------------------------------------------------- /land-of-lisp/cap11-attack-of-the-robots.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defun robots () 5 | (loop named main 6 | with directions = '((q . -65) (w . -64) (e . -63) (a . -1) 7 | (d . 1) (z . 63) (x . 64) (c . 65)) 8 | for pos = 544 9 | then (progn (format t "~%qwe/asd/zxc to move, (t)eleport, (l)eave: ") 10 | (force-output) 11 | (let* ((c (read)) 12 | (d (assoc c directions))) 13 | (cond (d (+ pos (cdr d))) 14 | ((eq 't c) (random 1024)) 15 | ((eq 'l c) (return-from main 'bye)) 16 | (t pos)))) 17 | for monsters = (loop repeat 10 18 | collect (random 1024)) 19 | then (loop for mpos in monsters 20 | collect (if (> (count mpos monsters) 1) 21 | mpos 22 | (cdar (sort (loop for (k . d) in directions 23 | for new-mpos = (+ mpos d) 24 | collect (cons (+ (abs (- (mod new-mpos 64) 25 | (mod pos 64))) 26 | (abs (- (ash new-mpos -6) 27 | (ash pos -6)))) 28 | new-mpos)) 29 | #'< 30 | :key #'car)))) 31 | when (loop for mpos in monsters 32 | always (> (count mpos monsters) 1)) 33 | return 'player-wins 34 | do (format t 35 | "~%|~{~<|~%|~,65:;~A~>~}|" 36 | (loop for p 37 | below 1024 38 | collect (cond ((member p monsters) 39 | (cond ((= p pos) (return-from main 'player-loses)) 40 | ((> (count p monsters) 1) #\#) 41 | (t #\A))) 42 | ((= p pos) #\@) 43 | (t #\space)))))) 44 | 45 | (princ (robots)) 46 | (fresh-line) 47 | -------------------------------------------------------------------------------- /land-of-lisp/cap11-format.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; :: Anatomy of the format function 5 | (format t "Add onion rings for only ~$ dollars more!" 1.5) 6 | ;; ARCH => (format &rest ) 7 | ;; STDOUT => "Add onion rings for only 1.50 dollars more" 8 | ;; RETURNS => nil 9 | 10 | ;; the destination parameter 11 | ;; nil => don't print anything; just return the value as a string 12 | ;; t => print the value to the console. In this case, the function just returns nil as a value (as in the example above) 13 | ;; stream => write the data to an output stream 14 | 15 | (princ (reverse 16 | (format nil "Add onion rings for only ~$ dollars more" 1.5))) 17 | ;; RETURNS => "erom srallod 05.1 ylno rof sgnir noino ddA" 18 | 19 | ;; :: The control string parameter 20 | 21 | ;; ~$ is a control sequence which indicates a `monetary floating-point` value 22 | ;; NOTE: Every control sequence recognized by the format functions begins with the tilde (~) character. 23 | 24 | ;; control sequences for printing lisp values 25 | 26 | (prin1 "foo") ;; => "FOO" 27 | (princ "foo") ;; => FOO 28 | 29 | ;; prin1 => machine usage 30 | ;; princ => human readable 31 | 32 | ;; A alternative way can be wrote using the format function with ~s and ~a 33 | ;; control sequences. 34 | 35 | (format t "I am printing ~s in the middle of this sentence." "foo") 36 | ;; => I am printing "foo" in the middle of this sentence. 37 | (format t "I am printing ~a in the middle of this sentence." "foo") 38 | ;; => I am printing foo in the middle of this sentence. 39 | 40 | 41 | ;; For example, by writing ~10a in the following example, we add seven spaces 42 | ;; to the right of foo, making the total width of the formatted value 10 chars. 43 | 44 | (format t "I am printing ~10a within ten spaces of room." "foo") 45 | ;; => I am printing foo within ten spaces of room. 46 | 47 | ;; We can also add spaces on the left side of the value by adding the @ symbol. 48 | 49 | (format t "I am printing ~10@a within ten spaces of room." "foo") 50 | ;; => I am printing foo within ten spaces of room. 51 | 52 | ;; control sequences can accept more than just one parameter. 53 | ;; Let's look at an example that sets the second param of the ~a control sequence as well: 54 | 55 | (format t "I am printing ~10,3a within then (or more) spaces of room." "foo") 56 | ;; => I am printing foo within then (or more) spaces of room. 57 | 58 | ;; As you can see, additional parameters to a control sequence are separated 59 | ;; with a comma. In this case, the second parameter is set to 3. Which tells 60 | ;; the format command to add spaces in groups of three until the goal width 61 | ;; of 10 is reached. In this example, a total of nine spaces are added to the 62 | ;; formatted value. This means it overshot our goal width of 10, leading 63 | ;; instead to a total width of 12. But using this feature is rare. 64 | 65 | ;; As well, a control sequence can has a third argument. 66 | 67 | (format t "I am printing ~,,4a in the middle of this sentence." "foo") 68 | ;; => I am printing foo in the middle of this sentence. 69 | 70 | ;; Exactly four spaces is added together with the foo symbol. 71 | 72 | ;; The fourth control sequence parameter specifies which character will be used 73 | ;; for padding. For example, in the following listing, we pad the printed 74 | ;; value with four exclamation points: 75 | 76 | (format t "The word ~,,4,'!a feels very important." "foo") 77 | ;; => The word foo!!!! feels very important. 78 | 79 | ;; We can combine the @ symbol with this example too. 80 | 81 | (format t "The word ~,,4,'!@a feels very important." "foo") 82 | ;; => The word !!!!foo feels very important. 83 | 84 | 85 | ;; :: Control Sequences for Formatting Numbers 86 | 87 | ;; the format command has many options designed specifically for controlling 88 | ;; the appearance of numbers. Let's look at some of the more useful ones. 89 | 90 | ;; -> Control Sequence for Formatting Integers 91 | ;; First, we can use format to display a number using a different base. For 92 | ;; instance we can display a number in hexadecimal (base-16) with the ~x control 93 | ;; sequence 94 | 95 | (format t "The number 1000 in hexadecimal is ~x" 1000) 96 | ;; => The number 1000 in hexadecimal is 3E8 97 | 98 | ;; Similarly, we can display a number in binary (base-2) using the ~b control 99 | ;; sequence 100 | 101 | (format t "The number 1000 in binary is ~b" 1000) 102 | ;; => The number 1000 in binary is 1111101000 103 | 104 | ;; We can even explicitly declare that a value will be displayed as a decimal 105 | ;; (base-10) number, using the ~d control sequence: 106 | (format t "The number 1000 in decimal is ~d" 1000) 107 | ;; => The number 1000 in decimal is 1000 108 | 109 | ;; The difference is that ~d supports special parameters and flags 110 | ;; that are specific to printing decimal numbers. For example, we can 111 | ;; place a colon inside the control sequence to enable commas as 112 | ;; digit group separators. 113 | 114 | (format t "Numbers with commas in them are ~:d times better." 1000000) 115 | ;; => Numbers with commas in them are 1,000,000 times better. 116 | 117 | ;; To control the width of the number, we can set the padding parameter, just 118 | ;; as we did with the ~a and ~s control sequences 119 | 120 | (format t "I am printing ~10d within ten spaces of room" 1000000) 121 | ;; => I am printing 1000000 within ten spaces of room 122 | 123 | ;; To change the character used for padding, pass in the desired character 124 | ;; (in this case, the x character) as the second parameter: 125 | 126 | (format t "I am printing ~10,'xd within ten spaces of room" 1000000) 127 | ;; => I am printing xxx1000000 within ten spaces of room 128 | 129 | 130 | ;; :: Control Sequences for Formatting Floating-Point Numbers 131 | 132 | ;; Floating-point values are handled with the ~f control sequence. 133 | ;; Controlling precision by max width size can be done: 134 | 135 | (format t "PI can be estimated as ~4f" 3.141593) 136 | ;; => PI can be estimated as 3.14 137 | 138 | 139 | ;; The second parameter of the ~f control sequence controls the number 140 | ;; of digits displayed after the decimal point. For example, if we pass 4 as 141 | ;; the second parameter in the preceding example, we get the following output: 142 | 143 | (format t "PI can be estimated as ~,4f" 3.141593) 144 | ;; => PI can be estimated as 3.1416 145 | 146 | ;; The third parameter of the ~f control sequence causes the number to 147 | ;; to be scaled by factors of ten. For example, we can pass 2 as the third parameter, 148 | ;; which we can use to multiply a fraction by 10² to turn it into a percentage 149 | (format t "Percentages are ~,,2f% better than fractions" 0.77) 150 | ;; => Percentages are 77.0% better than fractions 151 | 152 | ;; In addition to ~f, we can use the control sequence ~$, which is used for 153 | ;; formatting currencies 154 | (format t "I wish I had ~$ dollars in my bank account." 1000000.2) 155 | ;; => I wish I had 1000000.20 dollars in my bank account. 156 | 157 | ;; :: Printing Multiple Lines of Output 158 | 159 | ;; Common Lisp has two different commands for starting a new line during priting. 160 | ;; The first: terpri 161 | ;; Simply tells LISP to terminate the current line and start a new one for printing 162 | ;; subsequent output. For example, we can print two numbers on different lines like so. 163 | 164 | (progn (princ 22) 165 | (terpri) 166 | (princ 33)) 167 | 168 | ;; STDOUT => 22 169 | ;; 33 170 | 171 | ;; We can also start a new line with fresh-line. This command will start a new line, 172 | ;; but only if the cursor position in the REPL isn't already at the very front of a line. 173 | ;; This is seems be tricky, so let's look at some examples: 174 | 175 | (progn (princ 22) 176 | (fresh-line) 177 | (princ 33)) 178 | 179 | (progn (princ 22) 180 | (fresh-line) 181 | (fresh-line) 182 | (princ 33)) 183 | 184 | ;; The above programs has the same output: 185 | ;; STDOUT => 22 186 | ;; 33 187 | ;; In another words, terpri always print a new line; fresh-line only prints when is needed. 188 | 189 | 190 | ;; The format command has two control sequences equivalents to terpri and fresh-line 191 | ;; NOTE: WHAT THE FUCK!? WHY TERPRI AS NAME OF THIS TYPE OF FUNCTION? IS SO NON-SENSE. 192 | 193 | ;; ~% causes a new line to be created in all cases (like terpri) 194 | ;; ~& creates new lines only as needed (like fresh-line) 195 | 196 | ;; These examples illustrate this difference: 197 | 198 | (progn (format t "this is on one line ~%") 199 | (format t "~%this is on another line")) 200 | ;; STDOUT => 201 | ;; this is on one line 202 | ;; 203 | ;; this is on another line 204 | 205 | (progn (format t "this is on one line ~&") 206 | (format t "~&this is on another line")) 207 | ;; STDOUT => 208 | ;; this is on one line 209 | ;; this is on another line 210 | 211 | ;; As you can see, using an extra ~% prints an unsightly empty line and 212 | ;; using ~& in the same places does not. 213 | 214 | ;; These two line-termination sequences can also have an additional parameter 215 | ;; in front of them to indicate the number of new lines to be created. This is 216 | ;; useful in cases where we want to use empty lines to space out our output. 217 | ;; For example, the addition of 5 in the following examples adds five empty lines 218 | ;; to our output: 219 | 220 | (format t "this will print ~5% two lines spread far apart") 221 | ;; STDOUT => 222 | ;; this will print 223 | ;; 224 | ;; 225 | ;; 226 | ;; 227 | ;; two lines spread far apart 228 | 229 | 230 | ;; :: Justifying Output 231 | 232 | (defun random-animal () 233 | (nth (random 5) 234 | '("dog" "tick" "tiger" "walrus" "kangaroo"))) 235 | 236 | ;; now suppose we want to display a bunch of random animals in a table. 237 | ;; We can do this by using the ~t control sequence. ~t can take a parameter 238 | ;; that specifies the column position at which the formatted value should appear. 239 | ;; For example, to have our table of animals appear in three columns at the fifth, 240 | ;; fifteenth and twenty-fifth character positions, we could create this table 241 | 242 | (loop repeat 10 243 | do (format t "~5t~a ~15t~a ~25t~a~%" 244 | (random-animal) 245 | (random-animal) 246 | (random-animal))) 247 | 248 | ;; STDOUT => 249 | ;; dog tick walrus 250 | ;; kangaroo tiger walrus 251 | ;; dog dog dog 252 | ;; tick tick tiger 253 | ;; walrus kangaroo dog 254 | ;; walrus dog tick 255 | ;; dog kangaroo dog 256 | ;; dog walrus tiger 257 | ;; kangaroo walrus walrus 258 | ;; walrus tick tick 259 | 260 | 261 | ;; Now suppose we want all the animals be spaced equally apart on a single line. 262 | ;; To do so, we can use the ~< and ~> control sequences, as follows: 263 | 264 | (loop repeat 10 265 | do (format t "~30<~a~;~a~;~a~>~%" 266 | (random-animal) 267 | (random-animal) 268 | (random-animal))) 269 | ;; STDOUT => 270 | ;; tick tiger kangaroo 271 | ;; kangaroo walrus tiger 272 | ;; tiger kangaroo tiger 273 | ;; tiger kangaroo tiger 274 | ;; walrus tiger tick 275 | ;; kangaroo tick tiger 276 | ;; tiger walrus tiger 277 | ;; dog walrus tick 278 | ;; tiger tick dog 279 | ;; dog dog kangaroo 280 | 281 | 282 | ;; VERY VERY TRICKY 283 | ;; ~< and ~> is used to start and finish a text justifying operation 284 | 285 | ;; For example, we can create a single, neatly centered column as follows: 286 | 287 | (loop repeat 10 288 | do (format t "~30:@<~a~>~%" (random-animal))) 289 | 290 | 291 | ;; In the same way we can use :@ with multiple justified values, centering 292 | ;; them on the line with additional space at their left and right ends. 293 | 294 | (loop repeat 10 295 | do (format t "~30:@<~a~;~a~;~a~>~%" 296 | (random-animal) 297 | (random-animal) 298 | (random-animal))) 299 | 300 | ;; To produce neat collums, we'll still use the :@ flag, but we'll describe 301 | ;; our rows using three separate 10-character justification sections 302 | 303 | (loop repeat 10 304 | do (format t "~10:@<~a~>~10:@<~a~>~10:@<~a~>~%" 305 | (random-animal) 306 | (random-animal) 307 | (random-animal))) 308 | 309 | ;; STDOUT => 310 | ;; kangaroo walrus dog 311 | ;; kangaroo walrus kangaroo 312 | ;; tiger dog dog 313 | ;; kangaroo tiger dog 314 | ;; dog tick tiger 315 | ;; walrus tiger tiger 316 | ;; walrus dog dog 317 | ;; kangaroo walrus dog 318 | ;; walrus tick tick 319 | ;; tiger tick walrus 320 | 321 | 322 | ;; :: Iterating Through Lists Using Control Sequences 323 | 324 | ;; Format can loop through data using the ~{ and ~} control sequences 325 | 326 | (defparameter *animals* (loop repeat 10 collect (random-animal))) 327 | 328 | (format t "~{I see a ~a! ~}" *animals*) 329 | ;; STDOUT => I see a tick! I see a dog! I see a dog! I see a kangaroo! I see a tick! I see a dog! I see a walrus! I see a tick! I see a dog! I see a walrus! 330 | 331 | ;; To produce this loop, we simply pass the single variable *animals*, a list of items, 332 | ;; to the format function. The control string iterates through the list, constructing 333 | ;; the sentence "I see a ~a" for each member of *animals*. 334 | 335 | ;; A single iteration construct can also grab more than one item from the list, 336 | ;; as in this example: 337 | 338 | (format t "~{I see a ~a... or was it a ~a?~%~}" *animals*) 339 | ;; STDOUT => 340 | #| 341 | I see a tick... or was it a dog? 342 | I see a dog... or was it a kangaroo? 343 | I see a tick... or was it a dog? 344 | I see a walrus... or was it a tick? 345 | I see a dog... or was it a walrus? 346 | |# 347 | 348 | ;; We need be careful in this example above. If the number of elements is odd this 349 | ;; will cause a failure because the data is accessed by pairs. 350 | 351 | ;; :: A Crazy Formatting Trick for Creating Pretty Tables of Data 352 | 353 | (format t "|~{~<|~%|~,33:;~2d ~>~}|" (loop for x below 100 collect x)) 354 | ;; STDOUT => 355 | ;; | 0 1 2 3 4 5 6 7 8 9 | 356 | ;; |10 11 12 13 14 15 16 17 18 19 | 357 | ;; |20 21 22 23 24 25 26 27 28 29 | 358 | ;; |30 31 32 33 34 35 36 37 38 39 | 359 | ;; |40 41 42 43 44 45 46 47 48 49 | 360 | ;; |50 51 52 53 54 55 56 57 58 59 | 361 | ;; |60 61 62 63 64 65 66 67 68 69 | 362 | ;; |70 71 72 73 74 75 76 77 78 79 | 363 | ;; |80 81 82 83 84 85 86 87 88 89 | 364 | ;; |90 91 92 93 94 95 96 97 98 99 | 365 | 366 | ;; NEAT! 367 | -------------------------------------------------------------------------------- /land-of-lisp/cap12-socket-client.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (ql:quickload 'usocket) 5 | 6 | (princ "CLIENT: Trying connect to server... ") 7 | (defparameter *socket-connection* (usocket:socket-connect "127.0.0.1" 1234)) 8 | (defparameter *socket-stream* (usocket:socket-stream *socket-connection*)) 9 | (format t "Connected! ~%") 10 | 11 | (write-line "Yo Server!" *socket-stream*) 12 | (finish-output *socket-stream*) ;; force send messaging 13 | (format t ": ~a ~%" (read-line *socket-stream*)) 14 | 15 | (usocket:socket-close *socket-connection*) 16 | -------------------------------------------------------------------------------- /land-of-lisp/cap12-socket-server.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (ql:quickload 'usocket) 5 | 6 | ;; NOTE: in that example i need to force the stream with (finish-output) 7 | ;; to effectively send messages between sockets. 8 | 9 | ;; listening socket 10 | (defparameter *my-socket* (usocket:socket-listen "127.0.0.1" 1234)) 11 | 12 | (princ "SERVER: Waiting client connection... ") 13 | (finish-output) 14 | (defparameter *socket-connection* (usocket:socket-accept *my-socket*)) 15 | (defparameter *socket-stream* (usocket:socket-stream *socket-connection*)) 16 | (format t "Connected! ~%") 17 | ;; after running this command, the server will seem to lock up, 18 | ;; and you won't be returned to the REPL prompt. 19 | ;; Don't be alarmed, the socket-accept command is a blocking operation, 20 | ;; which means the function won't exit until a client has connected. 21 | 22 | (format t ": ~a ~%" (read-line *socket-stream*)) 23 | (write-line "What's up, Client!" *socket-stream*) 24 | (finish-output *socket-stream*) ;; flush buffered stream 25 | (usocket:socket-close *my-socket*) 26 | -------------------------------------------------------------------------------- /land-of-lisp/cap12-streams.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | #| 5 | :: => STREAMS 6 | 7 | Streams are data types in Common Lisp that allow you 8 | to take some external resource and make it look like 9 | just another simple piece of data you can manipulate with 10 | your code. 11 | 12 | Types of streams: 13 | * file stream: 14 | Let us read and write to files on our hard drive 15 | * string stream: 16 | Let us send and receive text from a Lisp string 17 | * console stream: 18 | REPL and terminals 19 | * socket stream: 20 | Let us communicate with other computers on a network 21 | 22 | Streams by direction: 23 | * output stream 24 | * input stream 25 | |# 26 | 27 | 28 | ;; Output Streams: 29 | ;; + Check whether the stream is valid 30 | ;; + Push a new item onto the stream 31 | 32 | ;; check if stream is valid 33 | (output-stream-p *standard-output*) 34 | ;; => T 35 | 36 | ;; push a new item on stream 37 | (write-char #\x *standard-output*) 38 | ;; STDOUT => x 39 | ;; => #\x 40 | 41 | 42 | ;; Input Streams 43 | ;; + check whether the stream is valid. 44 | ;; + pop an item off of the stream 45 | 46 | ;; check if the stream is valid 47 | (input-stream-p *standard-input*) 48 | ;; => T 49 | 50 | ;; pop item from stream 51 | (read-char *standard-input*) 52 | ;; INPUT => 123 53 | ;; => #\1 54 | 55 | ;; NOTE: Using other commands to interact with streams 56 | (print 'foo *standard-output*) 57 | 58 | 59 | ;; :: Working With Files 60 | 61 | ;; write on file 62 | (with-open-file (my-stream "data.txt" :direction :output) 63 | (print "my data" my-stream)) 64 | ;; => "my data" 65 | ;; a new file called data.txt is created 66 | 67 | 68 | ;; read a file 69 | (with-open-file (my-stream "data.txt" :direction :input) 70 | (read my-stream)) 71 | ;; => "my data" 72 | 73 | 74 | ;; another example 75 | (let ((animal-noises '((dog . woof) 76 | (cat . meow)))) 77 | (with-open-file (my-stream "animal-noises.txt" :direction :output) 78 | (print animal-noises my-stream))) 79 | ;; => ((DOG . WOOF) (CAT . MEOW)) 80 | 81 | (with-open-file (my-stream "animal-noises.txt" :direction :input) 82 | (read my-stream)) 83 | ;; => ((DOG . WOOF) (CAT . MEOW)) 84 | 85 | ;; using keywords of with-open-file form to throw errors 86 | ;; when a file already exists on direction output 87 | (with-open-file (my-stream "data.txt" :direction :output 88 | :if-exists :error) 89 | (print "my data" my-stream)) 90 | ;; *** - OPEN: file #P"/home/.../data.txt" already exists 91 | 92 | ;; use :supersede to force overwritten when :if-exists is true 93 | (with-open-file (my-stream "data.txt" :direction :output 94 | :if-exists :supersede) 95 | (print "my data" my-stream)) 96 | ;; => "my data" 97 | 98 | ;; NOTE: 99 | ;; The with-open-file macro is very similar to the context-manager of python 100 | ;; which is created using the `with` keyword on this language. 101 | ;; As well implement on Python, the with-open-file already cares about open 102 | ;; and closing the files gracefully. That way we don't need worry about that. 103 | ;; On Common Lisp, in general, all the `with-' commands using this prefix 104 | ;; will safely allocate resources in this way. 105 | 106 | 107 | ;; :: Working with Sockets 108 | 109 | ;; A socket is a mechanism for routing data over a computer network 110 | ;; between programs running on different computers on that network. 111 | ;; Sockets are not in the ANSI Common Lisp standard, which means 112 | ;; there's no standard way of interacting with sockets at this time. 113 | 114 | ;; libs: :cl-sockets or :usocket 115 | ;; cl-sockets is not in quicklisp, but usocket are. 116 | ;; in this section I'll use the usocket 117 | ;; https://github.com/usocket/usocket 118 | ;; running through SBCL 119 | ;; (ql:quickload 'usocket) 120 | 121 | ;; Every socket within a network must have a socket address: 122 | ;; + IP address 123 | ;; + Port number 124 | 125 | 126 | ;; -> Socket Connections 127 | ;; Steps: 128 | ;; 1. A program to create a socket that starts in a listening state (server) 129 | ;; 2. A program to create a socket its end and uses it to establish a connection with the server (client) 130 | ;; If all goes well, these two programs can now transmit messages across the socket connection running between them 131 | 132 | ;; This example will be write on the client and server files. 133 | ;; + cap12-socket-server.lisp 134 | ;; + cap12-socket-client.lisp 135 | 136 | 137 | ;; :: String Streams: The Oddball Type 138 | (defparameter foo (make-string-output-stream)) 139 | (princ "This will go into foo. " foo) 140 | (princ "This will also go into foo. " foo) 141 | (get-output-stream-string foo) 142 | 143 | 144 | ;; :: Reading and Debugging 145 | ;; Another reason for using string streams is that they can make our code 146 | ;; easier to read and debug, especially when we use the with-output-to- 147 | ;; string macro 148 | 149 | ;; Here's an example 150 | 151 | (with-output-to-string (*standard-output*) 152 | (princ "the sum of ") 153 | (princ 5) 154 | (princ " and ") 155 | (princ 2) 156 | (princ " is ") 157 | (princ (+ 2 5))) 158 | ;; => the sum of 5 and 2 is 7 159 | 160 | ;; The with-output-to-string macro will intercept any text that would 161 | ;; otherwise be output to the console, REPL, or other output stream, 162 | ;; and capture it as a string. 163 | 164 | ;; As a exercise of this chapter about streams as well about sockets, 165 | ;; I've wrote a experimental repository of chat-like system through 166 | ;; the local network at www.github.com/ryukinix/lisp-chat 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /land-of-lisp/cap13-error-handling.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; :: Signaling a Condition 5 | 6 | ;; Throwing a error: 7 | (error "foo") 8 | ;; => The REPL is interrupted 9 | ;; *** - foo 10 | 11 | ;; Using the error command will interrupt your running Lisp program 12 | ;; unless you intercept the error elsewhere to prevent an interruption. 13 | 14 | ;; :: Creating Custom Conditions 15 | 16 | ;; A more sophisticated way to signal conditions is to first 17 | ;; define a custom condition using `define-condition`, as here: 18 | 19 | (define-condition foo () () 20 | (:report (lambda (condition stream) 21 | (princ "Stop FOOing around, numbskull!" stream)))) 22 | 23 | (error 'foo) 24 | 25 | ;; => The REPL is interrupted 26 | ;; *** - Stop FOOing around, numbskull! 27 | 28 | ;; As you can see, our custom message was printed. This technique allows 29 | ;; the programmer to get a more meaningful error report, customized for the 30 | ;; specific condition that was triggered. 31 | 32 | ;; :: Intercepting Conditions 33 | 34 | (defun bad-function () 35 | (error 'foo)) 36 | 37 | (handler-case (bad-function) 38 | (foo () "somebody signaled foo!") 39 | (bar () "somebody signaled bar!")) 40 | 41 | ;; => "somebody signaled foo!" 42 | ;; Our handler-case command intercepts the foo condition that was be 43 | ;; signaled through the bad-function call. This means that the program 44 | ;; can keep running without interruption, with the handler-case evaluating 45 | ;; as "somebody signaled foo!" 46 | 47 | ;; :: Protecting Resources Against Unexpected Conditions 48 | ;; We can ignore exceptions too, like the unsafe operations of Rust. 49 | ;; Is like say "This piece of code must run no matter what happens" 50 | ;; To the Lisp compiler 51 | 52 | (unwind-protect (/ 1 0) 53 | (princ "I need to say 'flubyduby' matter what")) 54 | 55 | ;; Actually the exception is signaled and a interruption is made, but, 56 | ;; the other statements will still be executed. 57 | 58 | ;; => DIVISION-BY-ZERO error 59 | ;; ... after abort 60 | ;; => I need to say 'flubyduby' matter what 61 | 62 | ;; Within the unwind-protect, we divide by 0, which signals a condition. But 63 | ;; even after we tell to compiler to abort, the program still prints its 64 | ;; crucial message 65 | 66 | ;; We can usually avoid calling unwind-protect directly by relying on Common 67 | ;; Lisp "with-" macros; many of these call unwind-protect themselves, under 68 | ;; the hood. 69 | 70 | ;; NOTE: In the comic book epilogue at the end of the book, you'll learn 71 | ;; about and additional feature of the Common Lisp signaling system called 72 | ;; `restarts`. 73 | 74 | ;; The continuation of this chapter is written on the "cap13-webserver.lisp" 75 | -------------------------------------------------------------------------------- /land-of-lisp/cap13-webserver.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; :: Writing a Web Server from Scratch 5 | 6 | ;; -> How a Web Server Works 7 | 8 | ;; Hypertext Transfer Protocol, or HTTP, is the internet protocol 9 | ;; used for transferring web pages. It adds a layer on top of TCP/IP 10 | ;; for requesting pages once a socket connection has been established. 11 | ;; When a program running on a client computer (usually a web browser) 12 | ;; sends a properly encoded request, the server will retrieve the requested 13 | ;; page and send it over the socket stream in response. 14 | 15 | ;; NOTE: this web server is adapted from 'http.lisp' created by Ron Garret. 16 | 17 | ;; Decoding the Values of Request Parameters 18 | (ql:quickload 'usocket) 19 | 20 | (defpackage :webserver 21 | (:use :cl :usocket) 22 | (:export :serve)) 23 | 24 | (in-package :webserver) 25 | 26 | (defun http-char (c1 c2 &optional (default #\Space)) 27 | (let ((code (parse-integer 28 | (coerce (list c1 c2) 'string) 29 | :radix 16 30 | :junk-allowed t))) 31 | (if code 32 | (code-char code) 33 | default))) 34 | 35 | (defun decode-param (s) 36 | (labels ((f (list) 37 | (when list 38 | (case (car list) 39 | (#\% (cons (http-char (cadr list) (caddr list)) 40 | (f (cdddr list)))) 41 | (#\+ (cons #\space (f (cdr list)))) 42 | (otherwise (cons (car list) (f (cdr list)))))))) 43 | (coerce (f (coerce s 'list)) 44 | 'string))) 45 | 46 | ;; Unit tests 47 | (decode-param "foo") 48 | ;; => "foo" 49 | (decode-param "foo%3F") 50 | ;; => "foo?" 51 | (decode-param "foo+bar") 52 | ;; => "foo bar" 53 | 54 | ;; :: Decoding lists of request parameters 55 | 56 | (defun parse-params (s) 57 | (let ((i1 (position #\= s)) 58 | (i2 (position #\& s))) 59 | (cond (i1 (cons (cons (intern (string-upcase (subseq s 0 i1))) 60 | (decode-param (subseq s (1+ i1) i2))) 61 | (and i2 (parse-params (subseq s (1+ i2)))))) 62 | ((equal s "") nil) 63 | (t s)))) 64 | 65 | (parse-params "name=bob&age=25&gender=male") 66 | ;; => ((NAME . "bob") (AGE . "25") (GENDER . "male")) 67 | 68 | ;; NOTE: Both decode-param and parse-params could achieve higher performance 69 | ;; if they were written using a tail call, as we'll discuss in Chapter 14 70 | 71 | (defun parse-url (s) 72 | (let* ((url (subseq s 73 | (+ 2 (position #\space s)) 74 | (position #\space s :from-end t))) 75 | (x (position #\? url))) 76 | (if x 77 | (cons (subseq url 0 x) (parse-params (subseq url (1+ x)))) 78 | (cons url '())))) 79 | 80 | (parse-url "GET /lolcats.html HTTP/1.1") 81 | ;; => ("lolcats.html") 82 | (parse-url "GET /lolcats.html?extra-funny=yes HTTP/1.1") 83 | ;; => ("lolcats.html" (EXTRA-FUNNY . "yes")) 84 | 85 | 86 | (defun get-header (stream) 87 | (let* ((s (read-line stream)) 88 | (h (let ((i (position #\: s))) 89 | (when i 90 | (cons (intern (string-upcase (subseq s 0 i))) 91 | (subseq s (+ i 2))))))) 92 | (when h 93 | (cons h (get-header stream))))) 94 | 95 | ;; :: Testing get-header with a String stream 96 | 97 | (get-header (make-string-input-stream "foo: 1 98 | bar: abc, 123 99 | 100 | ")) 101 | ;; => ((FOO . "1") (BAR . "abc, 123")) 102 | ;; In that example we simulated a socket stream using a string stream with 103 | ;; input direction. Nice! 104 | 105 | ;; => Parse the Request Body 106 | 107 | (defun get-content-params (stream header) 108 | (let ((length (cdr (assoc 'content-length header)))) 109 | (when length 110 | (let ((content (make-string (parse-integer length)))) 111 | (read-sequence content stream) 112 | (parse-params content))))) 113 | 114 | 115 | ;; The server function is briefly modified to working with SBCL and USOCKET 116 | 117 | (defun serve (request-handler) 118 | (let ((socket (socket-listen "localhost" 8080))) 119 | (unwind-protect 120 | (loop (with-open-stream (stream (socket-stream (socket-accept socket))) 121 | (let* ((url (parse-url (read-line stream))) 122 | (path (car url)) 123 | (header (get-header stream)) 124 | (params (append (cdr url) 125 | (get-content-params stream header))) 126 | (*standard-output* stream)) 127 | (funcall request-handler path header params)))) 128 | (socket-close socket)))) 129 | 130 | 131 | ;; :: Building a Dynamic Website 132 | 133 | ;; To try out our shiny new web server, let's build a simple site that 134 | ;; greets a visitor, using the dirt-simple function hello-request-handler 135 | 136 | (defun hello-request-handler (path header params) 137 | (declare (ignore header)) 138 | (if (equal path "greeting") 139 | (let ((name (assoc 'name params))) 140 | (if (not name) 141 | (princ "
What is your name? 142 |
") 143 | (format t "Nice to meet you, ~a!" (cdr name)))) 144 | (princ "ERROR 404 - Sorry... I don't know that page"))) 145 | 146 | ;; (hello-request-handler "lolcats" '() '()) 147 | ;; => ERROR 404 - Sorry... I don't know that page 148 | 149 | ;; (hello-request-handler "greeting" '() ()) 150 | ;; =>
What is your name?
151 | 152 | ;; Executing the server... 153 | ;; (serve #'hello-request-handler) 154 | ;; You can access this server on 155 | ;; 127.0.0.1:8080/greeting 156 | 157 | ;; We now have a fully functioning web server and request handling infrastructure. 158 | -------------------------------------------------------------------------------- /land-of-lisp/cap14-functional-programming.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | #| 6 | -- Functional Programming 7 | 8 | In this chapter, you're going to learn about the first advanced 9 | Lisp concept, called the functional programming technique. 10 | 11 | Here are some important properties of mathematical functions that 12 | we'll want our Lisp functions to obey as well: 13 | 14 | + The function always returns the same result, as long as the same 15 | argument are passed into it. (This is often referred to as referential 16 | transparency) 17 | + The function never references variables that are defined outside the 18 | function, unless we are certain that these variables will remain 19 | constant 20 | + No variables are modified (or mutated, as functional programmers like 21 | to say) by the function. 22 | + The purpose of the function is to do nothing other than to return a 23 | result 24 | + The function doesn't do anything that is visible to the outside world, 25 | such as pop up a dialog box on the screen or make your computer go 26 | "Bing!" 27 | + The function doesn't take information from an outside source, such as 28 | the keyboard or the hard drive. 29 | 30 | |# 31 | 32 | 33 | ;; a great example of true mathematical function is the sine function 34 | 35 | (sin 0.5) 36 | ;; => 0.47942555 37 | 38 | 39 | ;; Whenever a piece of code does something that is visible to the outside 40 | ;; world, such as go "Bing!" or display a dialog box on the screen, 41 | ;; we say that the code causes a side effect. 42 | ;; Functional programmers think of such side effects as making your code 43 | ;; "dirty" 44 | 45 | 46 | ;; Let's give an example of a functional style program: 47 | 48 | ;; the clean, functional part 49 | (defun add-widget (database widget) 50 | (cons widget database)) 51 | 52 | ;; the dirty, non-functional part 53 | (defparameter *database* nil) 54 | (defun main-loop () 55 | (loop (princ "Please enter the name of a new widget: ") 56 | (setf *database* (add-widget *database* (read))) 57 | (format t "The database contains the following: ~{~a~^, ~}~%" *database*))) 58 | 59 | 60 | ;; NOTE: Some programming languages are even more focused on fp than Lisp is. 61 | ;; Haskell, for instance, has powerful features that let you write 99.9% of 62 | ;; your code in a functional style. In the end, however, your program will still 63 | ;; need to have some kind of side effect; otherwise, your code couldn't 64 | ;; accomplish anything useful. 65 | 66 | 67 | ;; :: Higher-Order Programming 68 | ;; The most powerful tool for code composition when writing functional 69 | ;; code is higher-order programming which lets you use functions that 70 | ;; accept other function as parameters. 71 | 72 | ;; Comparison between imperative style and functional style 73 | 74 | ;; -> imperative mode, add 2 to each element 75 | (defparameter *my-list* '(4 7 2 3) "a useless list") 76 | (loop for n below (length *my-list*) 77 | do (setf (nth n *my-list*) (+ (nth n *my-list*) 2))) 78 | ;; => NIL 79 | *my-list* ;; => (6 9 4 5) 80 | 81 | ;; + memory efficient (don't allocated new data) 82 | ;; + time efficient 83 | ;; - destroy data 84 | 85 | ;;; -> Using the functional style 86 | (defun add-two (list) 87 | (when list 88 | (cons (+ 2 (car list)) 89 | (add-two (cdr list))))) 90 | 91 | (add-two '(4 7 2 3)) 92 | ;; => '(6 9 4 5) 93 | 94 | ;; - memory inefficient (create new data) 95 | ;; + time efficient 96 | ;; + don't destroy data 97 | 98 | ;; Using Higher-Order functions 99 | (mapcar (lambda (x) 100 | (+ x 2)) 101 | '(4 7 2 3)) 102 | ;; => '(6 9 4 5) 103 | 104 | ;; Benefits of Functional Programming: 105 | ;; + Functional programming reduces bugs 106 | ;; + Functional programs are more compact 107 | ;; + Functional code is more elegant 108 | 109 | ;; Problems of Functional Programming: 110 | ;; - In general is inefficient¹ 111 | 112 | 113 | ;; ¹: for that, fp programmers, created techniques like: 114 | ;; Memoization, Tail Call Optimization, Higher-Order Programming 115 | ;; and another things. 116 | ;; Using good techniques a functional program can reach the same 117 | ;; performance of any other style. 118 | -------------------------------------------------------------------------------- /land-of-lisp/cap16-magic-with-macros.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | #| MACRO PROGRAMMING 5 | 6 | Allows you to mess around inside your Lisp compiler to turn Lisp into 7 | your own custom programming language. When faced with a difficult programming 8 | challenge, many experienced Lispers will first ask themselves: 9 | 10 | "What programming language could I use to make this problem easy to solve?" 11 | 12 | Then they'll use macros to convert Lisp into that language! 13 | |# 14 | 15 | ;; A Simple Lisp Macro 16 | 17 | ;; fancy let1 (simple let) 18 | (defmacro let1 (var val &body body) 19 | `(let ((,var ,val)) 20 | ,@body)) 21 | 22 | (let ((foo (+ 2 3))) 23 | (* foo foo)) 24 | 25 | (let1 foo (+ 2 3) 26 | (* foo foo)) 27 | 28 | (macroexpand '(let1 foo (+ 2 3) 29 | (* foo foo))) 30 | ;; .. EXPANSION .. 31 | ;; (LET ((FOO (+ 2 3))) 32 | ;; (* FOO FOO)) 33 | 34 | ;; More Complex Macros 35 | 36 | ;; Warning! Contains Bugs! 37 | (defmacro split (val yes no) 38 | `(if ,val 39 | (let ((head (car ,val)) 40 | (tail (cdr ,val))) 41 | ,yes) 42 | ,no)) 43 | 44 | (split '(1 2) 45 | (format t "head - tail <=> ~a - ~a" head tail) 46 | (format t "no head tail")) 47 | 48 | ;; Avoid Repeated Execution in Macros 49 | 50 | (macroexpand '(split (progn (princ "Lisp rocks!") 51 | '(2 3)) 52 | (format t "This can be split into ~a and ~a." head tail) 53 | (format t "This cannot be split."))) 54 | 55 | #| => 56 | (IF #1=(PROGN (PRINC "Lisp rocks!") '(2 3)) 57 | (LET ((HEAD (CAR #1#)) (TAIL (CDR #1#))) 58 | (FORMAT T "This can be split into ~a and ~a." HEAD TAIL)) 59 | (FORMAT T "This cannot be split.")) 60 | |# 61 | ;; the result above is optimized by SBCL 62 | ;; in another implementation, like SBCL, the val will be evaluated 63 | ;; two times, at which (princ "Lisp rocks!") will be printed three times 64 | 65 | ;; explicitly evaluation just one-time of val 66 | ;; Warning! Still contains bugs 67 | (defmacro split (val yes no) 68 | `(let1 x ,val 69 | (if x 70 | (let ((head (car x)) 71 | (tail (cdr x))) 72 | ,yes) 73 | ,no))) 74 | 75 | ;; (let1 x 100 76 | ;; (split '(2 3) 77 | ;; (+ x head) 78 | ;; nil)) 79 | ;; ERROR! '(2 3) is not a number 80 | 81 | (macroexpand '(split '(2 3) 82 | (+ x head) 83 | nil)) 84 | #| EXPANSION 85 | 86 | (LET ((X '(2 3))) 87 | (IF X 88 | (LET ((HEAD (CAR X)) (TAIL (CDR X))) 89 | (+ X HEAD)) 90 | NIL)) 91 | |# 92 | 93 | ;; So x <- 100 receive the new states '(2 3) 94 | ;; after the 'split macro expansion. 95 | ;; Pretty bad. 96 | 97 | 98 | ;; Use of gensym 99 | 100 | ;; This function is finally safe to use 101 | (defmacro split (val yes no) 102 | (let1 g (gensym) 103 | `(let1 ,g ,val 104 | (if ,g 105 | (let ((head (car ,g)) 106 | (tail (cdr ,g))) 107 | ,yes) 108 | ,no)))) 109 | 110 | 111 | (defun pairs (lst) 112 | (labels ((f (lst acc) 113 | (split lst 114 | (if tail 115 | (f (cdr tail) 116 | (cons (cons head (car tail)) 117 | acc)) 118 | (reverse acc)) 119 | (reverse acc)))) 120 | (f lst nil))) 121 | 122 | (pairs '(a b c d e f)) 123 | ;; => ((A . B) (C . D) (E . F)) 124 | 125 | (defmacro recurse (vars &body body) 126 | (let1 p (pairs vars) 127 | `(labels ((self ,(mapcar #'car p) 128 | ,@body)) 129 | (self ,@(mapcar #'cdr p))))) 130 | 131 | (recurse (n 10) 132 | (fresh-line) 133 | (if (= n 1) 134 | (princ "CANCER") 135 | (progn (princ n) 136 | (self (1- n))))) 137 | 138 | ;; my-length function using black magic macros 139 | (defun my-length (lst) 140 | (recurse (lst lst 141 | acc 0) 142 | (split lst 143 | (self tail (1+ acc)) 144 | acc))) 145 | 146 | (my-length '(1 2 3)) 147 | 148 | ;; functional way (alternative to macro techniques) 149 | (defun my-length (lst) 150 | (reduce (lambda (x _) 151 | (declare (ignore _)) 152 | (1+ x)) 153 | lst 154 | :initial-value 0)) 155 | -------------------------------------------------------------------------------- /land-of-lisp/cap17-domain-specific-languages.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; On this chapter we'll create a SVG handler DSL using macros 5 | ;; Remember SVG (Scalable Vector Graphics) are XML-like, 6 | 7 | 8 | (defpackage :svg 9 | (:use :cl) 10 | (:export :svg :html 11 | :body :tag 12 | :brightness :svg-style 13 | :polygon :circle)) 14 | 15 | (in-package :svg) 16 | 17 | 18 | ;; Would be better avoid copy-paste functions, 19 | ;; but the chapter 16 has several re-definitions 20 | ;; and top-level execution of demonstrations 21 | ;; So i just adapted the +SPLIT and +PAIRS functions 22 | 23 | (defmacro split (val yes no) 24 | "Exported from the chapter 16" 25 | (let ((g (gensym))) 26 | `(let ((,g ,val)) 27 | (if ,g 28 | (let ((head (car ,g)) 29 | (tail (cdr ,g))) 30 | ,yes) 31 | ,no)))) 32 | 33 | 34 | (defun pairs (lst) 35 | "Exported from the chapter 16" 36 | (labels ((f (lst acc) 37 | (split lst 38 | (if tail 39 | (f (cdr tail) 40 | (cons (cons head (car tail)) 41 | acc)) 42 | (reverse acc)) 43 | (reverse acc)))) 44 | (f lst nil))) 45 | 46 | ;; so we need create tags 47 | (defun print-tag (name alist closingp) 48 | (princ #\<) 49 | (when closingp 50 | (princ #\/)) 51 | (princ (string-downcase name)) 52 | (mapc (lambda (att) 53 | (format t " ~a=\"~a\"" 54 | (string-downcase (car att)) 55 | (cdr att))) 56 | alist) 57 | (princ #\>)) 58 | 59 | 60 | (defmacro tag (name atts &body body) 61 | `(progn (print-tag ',name 62 | (list ,@(mapcar (lambda (x) 63 | `(cons ',(car x) 64 | ,(cdr x))) 65 | (pairs atts))) 66 | nil) 67 | ,@body 68 | (print-tag ',name nil t))) 69 | 70 | ;; using syntax-sugar for html 71 | 72 | (defmacro html (&body body) 73 | `(tag html () 74 | ,@body)) 75 | 76 | (defmacro body (&body body) 77 | `(tag body () 78 | ,@body)) 79 | 80 | (defmacro svg (&body body) 81 | `(tag svg (xmlns "http://www.w3.org/2000/svg" 82 | "xmlns:xlink" "http://www.w3.org/1999/xlink") 83 | ,@body)) 84 | 85 | (defun brightness (col amt) 86 | (mapcar (lambda (x) 87 | (min 255 (max 0 (+ x amt)))) 88 | col)) 89 | 90 | (defun svg-style (color) 91 | (format nil 92 | "~{fill:rgb(~a,~a,~a);stroke:rgb(~a,~a,~a)~}" 93 | (append color 94 | (brightness color -100)))) 95 | 96 | (defun circle (center radius color) 97 | (tag circle (cx (car center) 98 | cy (cdr center) 99 | r radius 100 | style (svg-style color)))) 101 | 102 | (defun polygon (points color) 103 | (tag polygon (points (format nil 104 | "~{~a, ~a ~}" 105 | (mapcan (lambda (tp) 106 | (list (car tp) (cdr tp))) 107 | points)) 108 | style (svg-style color)))) 109 | 110 | 111 | (defun random-walk (value length) 112 | (unless (zerop length) 113 | (cons value 114 | (random-walk (if (zerop (random 2)) 115 | (1- value) 116 | (1+ value)) 117 | (1- length))))) 118 | 119 | 120 | ;; create random polygons at random_walk.svg 121 | 122 | (defun random-walk-svg () 123 | (with-open-file (*standard-output* "random_walk.svg" 124 | :direction :output 125 | :if-exists :supersede) 126 | (svg (loop repeat 10 127 | do (polygon (append '((0 . 200)) 128 | (loop for x from 0 129 | for y in (random-walk 100 400) 130 | collect (cons x y)) 131 | '((400 . 200))) 132 | (loop repeat 3 133 | collect (random 256))))))) 134 | 135 | 136 | ;; svg finished 137 | 138 | ;; starts extension of the wizard_game from chapter 5-6 139 | -------------------------------------------------------------------------------- /land-of-lisp/cap17-text-game-adventure-v2.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (load "cap5-building-a-text-game-engine") 5 | 6 | 7 | (defun have (object) 8 | (member object (inventory))) 9 | 10 | (defparameter *chain-welded* nil) 11 | 12 | (defun weld (subject object) 13 | (if (and (eq *location* 'attic) 14 | (eq subject 'chain) 15 | (eq object 'bucket) 16 | (have 'chain) 17 | (have 'bucket) 18 | (not *chain-welded*)) 19 | (progn (setf *chain-welded* t) 20 | '(the chain is now securely welded to the bucket.)) 21 | '(you cannot weld like that.))) 22 | 23 | (pushnew 'weld *allowed-commands*) 24 | (defparameter *bucket-filled* nil) 25 | 26 | (defun dunk (subject object) 27 | (if (and (eq *location* 'garden) 28 | (eq subject 'bucket) 29 | (eq object 'well) 30 | (have 'bucket) 31 | *chain-welded*) 32 | (progn (setf *bucket-filled* t) 33 | '(the bucket is now full of water)) 34 | '(you cannot dunk like that))) 35 | (pushnew 'dunk *allowed-commands*) 36 | 37 | 38 | ;; super cool macro to avoid replication like the commands above 39 | (defmacro game-action (command subj obj place &body body) 40 | `(progn (defun ,command (subject object) 41 | (if (and (eq *location* ',place) 42 | (eq subject ',subj) 43 | (eq object ',obj) 44 | (have ',subj)) 45 | ,@body 46 | '(i cant ,command like that.))) 47 | (pushnew ',command *allowed-commands*))) 48 | 49 | (game-action splash bucket wizard living-room 50 | (cond ((not *bucket-filled*) '(the bucket has nothing in it.)) 51 | ((have 'frog) '(the wizard awakens and sees that you stole his frog. 52 | he is so upset he banishes you to the netherworlds- 53 | you lose! the end.)) 54 | (t '(the wizard awakens from his slumber and greets your warmly. 55 | he hands you the magic low-carb donut- you win! the end.)))) 56 | -------------------------------------------------------------------------------- /land-of-lisp/cap18-dice-of-doom-v2.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (load "cap15-dice-of-doom") ;; load as package dice-doom 5 | (load "cap18-lazy-programming") ;; load directly to cl-user 6 | 7 | (defpackage :dice-of-doom-v2 8 | (:use :cl :dice-of-doom :lazy) 9 | (:export :human 10 | :winners 11 | :computer 12 | :handle-computer 13 | :gen-board 14 | :game-tree 15 | :player-letter 16 | :*ai-level* 17 | :*num-players* 18 | :*max-dice* 19 | :*board-size* 20 | :*board-hexnum*)) 21 | 22 | (in-package dice-of-doom-v2) 23 | 24 | 25 | (defparameter *board-size* 4) 26 | (defparameter *board-hexnum* (* *board-size* 27 | *board-size*)) 28 | 29 | (defun add-passing-move (board player spare-dice first-move moves) 30 | (if first-move 31 | moves 32 | (lazy-cons (list nil 33 | (game-tree (add-new-dice board player 34 | (1- spare-dice)) 35 | (mod (1+ player) *num-players*) 36 | 0 37 | t)) 38 | moves))) 39 | 40 | 41 | (defun attacking-moves (board cur-player spare-dice) 42 | (labels ((player (pos) 43 | (car (aref board pos))) 44 | (dice (pos) 45 | (cadr (aref board pos)))) 46 | (lazy-mapcan 47 | (lambda (src) 48 | (if (eq (player src) cur-player) 49 | (lazy-mapcan 50 | (lambda (dst) 51 | (if (and (not (eq (player dst) 52 | cur-player)) 53 | (> (dice src) (dice dst))) 54 | (make-lazy 55 | (list (list (list src dst) 56 | (game-tree (board-attack board 57 | cur-player 58 | src 59 | dst 60 | (dice src)) 61 | cur-player 62 | (+ spare-dice (dice dst)) 63 | nil)))) 64 | (lazy-nil))) 65 | (make-lazy (neighbors src))) 66 | (lazy-nil))) 67 | (make-lazy (loop for n below *board-hexnum* 68 | collect n))))) 69 | 70 | (defun handle-human (tree) 71 | (fresh-line) 72 | (princ "choose your move:") 73 | (let ((moves (caddr tree))) 74 | (labels ((print-moves (moves n) 75 | (unless (null moves) ;; hacky fix 76 | (unless (lazy-null moves) 77 | (let* ((move (lazy-car moves)) 78 | (action (car move))) 79 | (fresh-line) 80 | (format t "~a. " n) 81 | (if action 82 | (format t "~a -> ~a" (car action) (cadr action)) 83 | (princ "end turn")))) 84 | (print-moves (lazy-cdr moves) (1+ n))))) 85 | (print-moves moves 1)) 86 | (fresh-line) 87 | (cadr (lazy-nth (1- (read)) moves)))) 88 | 89 | (defun play-vs-human (tree) 90 | (print-info tree) (if (not (lazy-null (caddr tree))) 91 | (play-vs-human (handle-human tree)) 92 | (announce-winner (cadr tree)))) 93 | 94 | 95 | (defun limit-tree-depth (tree depth) 96 | (list (car tree) 97 | (cadr tree) 98 | (if (zerop depth) 99 | (lazy-nil) 100 | (lazy-mapcar (lambda (move) 101 | (list (car move) 102 | (limit-tree-depth (cadr move) (1- depth)))) 103 | (caddr tree))))) 104 | 105 | 106 | (defparameter *ai-level* 4) ;; depth to look on tree of game 107 | 108 | ;; OLD NON-OPTIMIZED COMPUTER AI 109 | ;; (defun handle-computer (tree) 110 | ;; (let ((ratings (get-ratings (limit-tree-depth tree *ai-level*) 111 | ;; (car tree)))) 112 | ;; (cadr (lazy-nth (position (apply #'max ratings) ratings) 113 | ;; (caddr tree))))) 114 | 115 | 116 | (defun play-vs-computer (tree) 117 | (print-info tree) 118 | (cond ((lazy-null (caddr tree)) (announce-winner (cadr tree))) 119 | ((zerop (car tree)) (play-vs-computer (handle-human tree))) 120 | (t (play-vs-computer (handle-computer tree))))) 121 | 122 | (defun threatened (pos board) 123 | (let* ((hex (aref board pos)) 124 | (player (car hex)) 125 | (dice (cadr hex))) 126 | (loop for n in (neighbors pos) 127 | do (let* ((nhex (aref board n)) 128 | (nplayer (car nhex)) 129 | (ndice (cadr nhex))) 130 | (when (and (not (eq player nplayer)) 131 | (> ndice dice)) 132 | (return t)))))) 133 | 134 | 135 | (defun score-board (board player) 136 | (loop for hex across board 137 | for pos from 0 138 | sum (if (eq (car hex) player) 139 | (if (threatened pos board) 140 | 1 141 | 2) 142 | -1))) 143 | 144 | (defun get-ratings (tree player) 145 | (take-all (lazy-mapcar (lambda (move) 146 | (rate-position (cadr move) player)) 147 | (caddr tree)))) 148 | 149 | (defun rate-position (tree player) 150 | (let ((moves (caddr tree))) 151 | (if (not (lazy-null moves)) 152 | (apply (if (eq (car tree) player) 153 | #'min 154 | #'max) 155 | (get-ratings tree player)) 156 | (get-ratings tree player)) 157 | (score-board (cadr tree) player))) 158 | 159 | ;; The next functions will be just a optimization of AI algorithm 160 | ;; to exclude bad branches on game tree using the Alpha-beta technique 161 | 162 | 163 | (defun ab-rate-position (tree player upper-limit lower-limit) 164 | (let ((moves (caddr tree))) 165 | (if (not (lazy-null moves)) 166 | (if (eq (car tree) player) 167 | (apply #'max (ab-get-ratings-max tree 168 | player 169 | upper-limit 170 | lower-limit)) 171 | (apply #'min (ab-get-ratings-min tree 172 | player 173 | upper-limit 174 | lower-limit))) 175 | (score-board (cadr tree) player)))) 176 | 177 | 178 | (defun ab-get-ratings-max (tree player upper-limit lower-limit) 179 | (labels ((f (moves lower-limit) 180 | (unless (lazy-null moves) 181 | (let ((x (ab-rate-position (cadr (lazy-car moves)) 182 | player 183 | upper-limit 184 | lower-limit))) 185 | (if (>= x upper-limit) 186 | (list x) 187 | (cons x (f (lazy-cdr moves) 188 | (max x lower-limit)))))))) 189 | (f (caddr tree) lower-limit))) 190 | 191 | 192 | (defun ab-get-ratings-min (tree player upper-limit lower-limit) 193 | (labels ((f (moves upper-limit) 194 | (unless (lazy-null moves) 195 | (let ((x (ab-rate-position (cadr (lazy-car moves)) 196 | player 197 | upper-limit 198 | lower-limit))) 199 | (if (<= x lower-limit) 200 | (list x) 201 | (cons x (f (lazy-cdr moves) 202 | (min x upper-limit)))))))) 203 | (f (caddr tree) upper-limit))) 204 | 205 | 206 | (defun handle-computer (tree) 207 | (let ((ratings (ab-get-ratings-max (limit-tree-depth tree *ai-level*) 208 | (car tree) 209 | most-positive-fixnum 210 | most-negative-fixnum))) 211 | (cadr (lazy-nth (position (apply #'max ratings) ratings) (caddr tree))))) 212 | 213 | 214 | (defparameter *board-size* 5) 215 | (defparameter *board-hexnum* (* *board-size* *board-size*)) 216 | -------------------------------------------------------------------------------- /land-of-lisp/cap18-lazy-programming.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; LAZY PROGRAMMING 5 | 6 | ;; PROG: Creating the Lazy and Force Commands 7 | ;; NOTE: This chapter has a lazy evaluation system very similar 8 | ;; to discussed on the lectures about STREAMS (6A-6B) of SICP at MIT. 9 | 10 | (defpackage :lazy 11 | (:use :cl) 12 | (:export :lazy 13 | :force 14 | :lazy-cons 15 | :lazy-car 16 | :lazy-cdr 17 | :lazy-nil 18 | :lazy-null 19 | :make-lazy 20 | :take 21 | :take-all 22 | :lazy-mapcar 23 | :lazy-mapcan 24 | :lazy-find-if 25 | :lazy-nth 26 | :*integers*)) 27 | 28 | (in-package :lazy) 29 | 30 | (defmacro lazy (&body body) 31 | (let ((forced (gensym)) 32 | (value (gensym))) 33 | `(let ((,forced nil) 34 | (,value nil)) 35 | (lambda () 36 | (unless ,forced 37 | (setf ,value (progn ,@body)) 38 | (setf ,forced t)) 39 | ,value)))) 40 | 41 | (defun force (lazy-value) 42 | (funcall lazy-value)) 43 | 44 | 45 | (defmacro lazy-cons (a b) 46 | `(lazy (cons ,a ,b))) 47 | 48 | (defun lazy-car (x) 49 | (car (force x))) 50 | 51 | (defun lazy-cdr (x) 52 | (cdr (force x))) 53 | 54 | (defparameter *foo* (lazy-cons 4 7)) ;; => CLOSURE LAMBDA 55 | (lazy-car *foo*) ;; => 4 56 | (lazy-cdr *foo*) ;; => 7 57 | 58 | 59 | (defparameter *integers* (labels ((f (n) 60 | (lazy-cons n (f (1+ n))))) 61 | (f 1))) 62 | 63 | (lazy-car *integers*) ;; => 1 64 | (lazy-car (lazy-cdr *integers*)) ;; => 2 65 | (lazy-car (lazy-cdr (lazy-cdr *integers*))) ;; => 3 66 | 67 | ;; YES! INFINITE SEQUENCES! This is the lazy evaluation power 68 | ;; Only computes the value when needs. No recursive stack overflow. 69 | 70 | 71 | (defun lazy-nil () 72 | (lazy nil)) 73 | 74 | (defun lazy-null (x) 75 | (not (force x))) 76 | 77 | 78 | (defun make-lazy (list) 79 | (lazy (when list 80 | (cons (car list) 81 | (make-lazy (cdr list)))))) 82 | 83 | 84 | (defun take (n list) 85 | (unless (or (zerop n) 86 | (lazy-null list)) 87 | (cons (lazy-car list) 88 | (take (1- n) (lazy-cdr list))))) 89 | 90 | (take 100 *integers*) ;; => '(1 2 3 4 5 6 7 8 9 10) 91 | 92 | (defun take-all (list) 93 | (unless (lazy-null list) 94 | (cons (lazy-car list) 95 | (take-all (lazy-cdr list))))) 96 | 97 | (take 10 (make-lazy '(q w e r t y u i o p a s d f))) 98 | ;; => (Q W E R T Y U I O P) 99 | 100 | (take-all (make-lazy '(q w e r t y u i o p a s d f))) 101 | ;; => (Q W E R T Y U I O P A S D F) 102 | 103 | 104 | (defun lazy-mapcar (fun list) 105 | (lazy (unless (lazy-null list) 106 | (cons (funcall fun (lazy-car list)) 107 | (lazy-mapcar fun (lazy-cdr list)))))) 108 | 109 | (defun lazy-mapcan (fun list) 110 | (labels ((f (list-cur) 111 | (if (lazy-null list-cur) 112 | (force (lazy-mapcan fun (lazy-cdr list))) 113 | (cons (lazy-car list-cur) 114 | (lazy (f (lazy-cdr list-cur))))))) 115 | (lazy (unless (lazy-null list) 116 | (f (funcall fun (lazy-car list))))))) 117 | 118 | (defun lazy-find-if (fun list) 119 | (unless (lazy-null list) 120 | (let ((x (lazy-car list))) 121 | (if (funcall fun x) 122 | x 123 | (lazy-find-if fun (lazy-cdr list)))))) 124 | 125 | (defun lazy-nth (n list) 126 | (if (zerop n) 127 | (lazy-car list) 128 | (lazy-nth (1- n) (lazy-cdr list)))) 129 | 130 | 131 | ;; NOTE: Analogous functions mapcar, mapcan, find-if and nth for lazy lists. 132 | (take 10 (lazy-mapcar #'sqrt *integers*)) 133 | ;; => (1.0 1.4142135 1.7320508 2.0 2.236068 2.4494898 2.6457512 2.828427 3.0 3.1622777) 134 | 135 | (take 10 (lazy-mapcan (lambda (x) 136 | (if (evenp x) 137 | (make-lazy (list x)) 138 | (lazy-nil))) 139 | *integers*)) 140 | ;; => (2 4 6 8 10 12 14 16 18 20) 141 | 142 | (lazy-find-if #'oddp (make-lazy '(2 4 6 7 8 10))) 143 | ;; => 7 144 | 145 | (lazy-nth 4 (make-lazy '(a b c d e f g))) 146 | ;; => E 147 | -------------------------------------------------------------------------------- /land-of-lisp/cap19-web-dice-of-doom-v3.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (load "cap13-webserver") ;; as :webserver package 5 | (load "cap17-domain-specific-languages") ;; as :svg package 6 | (load "cap18-dice-of-doom-v2") ;; as :dice-of-doom-v2 package 7 | (load "cap18-lazy-programming") ;; as :lazy package 8 | 9 | (defpackage :dice-of-doom-v3 10 | (:use :cl :svg :dice-of-doom-v2 :lazy :webserver) 11 | (:export :main 12 | :gen-board 13 | :attacking-moves 14 | :handle-human 15 | :handle-computer 16 | :get-ratings 17 | :limit-tree-depth 18 | :*num-players* 19 | :*die-colors* 20 | :*ai-level* 21 | :*board-width* :*board-height* 22 | :*board-scale* :*top-offset* 23 | :*dice-scale* :*dot-size*)) 24 | 25 | (in-package :dice-of-doom-v3) 26 | 27 | 28 | (defparameter *board-width* 900) 29 | (defparameter *board-height* 500) 30 | (defparameter *board-scale* 64) 31 | (defparameter *top-offset* 3) 32 | (defparameter *dice-scale* 40) 33 | (defparameter *dot-size* 0.05) 34 | (defparameter *die-colors* '((255 63 63) (63 63 255))) 35 | (defparameter *cur-game-tree* nil) 36 | (defparameter *from-tile* nil) 37 | 38 | (defun draw-die-svg (x y col) 39 | (labels ((calc-pt (pt) 40 | (cons (+ x (* *dice-scale* (car pt))) 41 | (+ y (* *dice-scale* (cdr pt))))) 42 | (f (pol col) 43 | (polygon (mapcar #'calc-pt pol) col))) 44 | (f '((0 . -1) (-0.6 . -0.75) (0 . -0.5) (0.6 . -0.75)) 45 | (brightness col 40)) 46 | (f '((0 . -0.5) (-0.6 . -0.75) (-0.6 . 0) (0 . 0.25)) 47 | col) 48 | (f '((0 . -0.5) (0.6 . -0.75) (0.6 . 0) (0 . 0.25)) 49 | (brightness col -40)) 50 | (mapc (lambda (x y) 51 | (polygon (mapcar (lambda (xx yy) 52 | (calc-pt (cons (+ x (* xx *dot-size*)) 53 | (+ y (* yy *dot-size*))))) 54 | '(-1 -1 1 1) 55 | '(-1 1 1 -1)) 56 | '(255 255 255))) 57 | '(-0.05 0.125 0.3 -0.3 -0.125 0.05 0.2 0.2 0.45 0.45 -0.45 -0.2) 58 | '(-0.875 -0.80 -0.725 -0.775 -0.70 -0.625 59 | -0.35 -0.05 -0.45 -0.15 -0.45 -0.05)))) 60 | 61 | (defun draw-tile-svg (x y pos hex xx yy col chosen-tile) 62 | (loop for z below 2 63 | do (polygon (mapcar (lambda (pt) 64 | (cons (+ xx (* *board-scale* (car pt))) 65 | (+ yy (* *board-scale* 66 | (+ (cdr pt) (* (- 1 z) 0.1)))))) 67 | 68 | '((-1 . -0.2) (0 . -0.5) (1 . -0.2) 69 | (1 . 0.2) (0 . 0.5) (-1 . 0.2))) 70 | (if (eql pos chosen-tile) 71 | (brightness col 100) 72 | col))) 73 | (loop for z below (second hex) 74 | do (draw-die-svg (+ xx 75 | (* *dice-scale* 76 | 0.3 77 | (if (oddp (+ x y z)) 78 | -0.3 79 | 0.3))) 80 | (- yy (* *dice-scale* z 0.8)) col))) 81 | 82 | (defun make-game-link (pos) 83 | (format nil "/game.html?chosen=~a" pos)) 84 | 85 | 86 | (defun draw-board-svg (board chosen-tile legal-tiles) 87 | (loop for y below *board-size* 88 | do (loop for x below *board-size* 89 | for pos = (+ x (* *board-size* y)) 90 | for hex = (aref board pos) 91 | for xx = (* *board-scale* (+ (* 2 x) (- *board-size* y))) 92 | for yy = (* *board-scale* (+ (* y 0.7) *top-offset*)) 93 | for col = (brightness (nth (first hex) *die-colors*) 94 | (* -15 (- *board-size* y))) 95 | do (if (member pos legal-tiles) 96 | (tag g () 97 | (tag a ("xlink:href" (make-game-link pos)) 98 | (draw-tile-svg x y pos hex xx yy col chosen-tile))) 99 | (draw-tile-svg x y pos hex xx yy col chosen-tile))))) 100 | 101 | 102 | (defun web-initialize () 103 | (setf *from-tile* nil) 104 | (setf *cur-game-tree* (game-tree (gen-board) 0 0 t))) 105 | 106 | (defun web-announce-winner (board) 107 | (fresh-line) 108 | (let ((w (winners board))) 109 | (if (> (length w) 1) 110 | (format t "The game is a tie between ~a" (mapcar #'player-letter w)) 111 | (format t "The winner is ~a" (player-letter (car w))))) 112 | (tag a (href "game.html") 113 | (princ " play again"))) 114 | 115 | (defun web-handle-human (pos) 116 | (cond ((not pos) (princ "Please choose a hex to move from:")) 117 | ((eq pos 'pass) (setf *cur-game-tree* 118 | (cadr (lazy-car (caddr *cur-game-tree*)))) 119 | (princ "Your reinforcements have been placed.") 120 | (tag a (href (make-game-link nil)) 121 | (princ "continue"))) 122 | ((not *from-tile*) (setf *from-tile* pos) 123 | (princ "Now choose a destination:")) 124 | ((eq pos *from-tile*) (setf *from-tile* nil) 125 | (princ "Move cancelled.")) 126 | (t (setf *cur-game-tree* 127 | (cadr (lazy-find-if (lambda (move) 128 | (equal (car move) 129 | (list *from-tile* pos))) 130 | (caddr *cur-game-tree*)))) 131 | (setf *from-tile* nil) 132 | (princ "You may now ") 133 | (tag a (href (make-game-link 'pass)) 134 | (princ "pass")) 135 | (princ " or make another move:")))) 136 | 137 | (defun web-handle-computer () 138 | (setf *cur-game-tree* (handle-computer *cur-game-tree*)) 139 | (princ "The computer has moved. ") 140 | (tag script () 141 | (princ "window.setTimeout('window.location=\"game.html?chosen=NIL\"',5000)"))) 142 | 143 | (defun draw-dod-page (tree selected-tile) 144 | (svg *board-width* 145 | *board-height* 146 | (draw-board-svg (cadr tree) 147 | selected-tile 148 | (take-all (if selected-tile 149 | (lazy-mapcar 150 | (lambda (move) 151 | (when (eql (caar move) 152 | selected-tile) 153 | (cadar move))) 154 | (caddr tree)) 155 | (lazy-mapcar #'caar (caddr tree))))))) 156 | 157 | 158 | 159 | (defun dod-request-handler (path header params) 160 | (declare (ignore header)) 161 | (if (equal path "game.html") 162 | (progn (html 163 | (body 164 | (tag center () 165 | (princ "Welcome to DICE OF DOOM!") 166 | (tag br ()) 167 | (let ((chosen (assoc 'chosen params))) 168 | (when (or (not *cur-game-tree*) 169 | (not chosen)) 170 | (setf chosen nil) 171 | (web-initialize)) 172 | (cond ((lazy-null (caddr *cur-game-tree*)) 173 | (web-announce-winner (cadr *cur-game-tree*))) 174 | ((zerop (car *cur-game-tree*)) 175 | (web-handle-human 176 | (when chosen 177 | (read-from-string (cdr chosen))))) 178 | (t (web-handle-computer)))) 179 | (tag br ()) 180 | (draw-dod-page *cur-game-tree* *from-tile*))))) 181 | (princ "Sorry... I don't know that page."))) 182 | 183 | 184 | (defun main () 185 | (serve #'dod-request-handler)) 186 | 187 | 188 | ;; NOTE: 189 | ;; UNFORTUNATELY THIS EXAMPLE DOESN'T WORKS ON MODERN BROWSERS 190 | ;; BECAUSE THE BAD IMPLEMENTATION OF :WEBSERVER WITHOUT SEND A STANDARD HEADER. 191 | 192 | ;; By the way, the svg drawing is fucked up too. GREAT. 193 | -------------------------------------------------------------------------------- /land-of-lisp/cap2-guess-my-number.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defun guess-my-number () 5 | (ash (+ *small* *big*) -1)) 6 | 7 | (defun smaller () 8 | (setf *big* (1- (guess-my-number))) 9 | (guess-my-number)) 10 | 11 | (defun bigger () 12 | (setf *small* (1+ (guess-my-number))) 13 | (guess-my-number)) 14 | 15 | (defun start-over () 16 | (defparameter *small* 1) 17 | (defparameter *big* 100) 18 | (guess-my-number)) 19 | -------------------------------------------------------------------------------- /land-of-lisp/cap20-dice-of-doom-v4.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defpackage :dice-of-doom-v4 5 | (:use :cl :dice-of-doom-v3)) 6 | 7 | (in-package :dice-of-doom-v4) 8 | 9 | 10 | ;; YES, MORE PLAYERS 11 | (defparameter *num-players* 4) 12 | (defparameter *die-colors* '((255 63 63) (63 63 255) (63 255 63) 13 | (255 63 255))) 14 | (defparameter *max-dice* 5) 15 | (defparameter *ai-level* 2) 16 | 17 | #| 18 | 19 | LISP OVERHEAT 20 | 21 | I'm tired of this shit example of DICE OF DOOM! THIS IS NOT FUN. 22 | 23 | Go to hell web-based games. 24 | 25 | |# 26 | 27 | ;; NOTE: Skipping this chapter. I'll note write a new version of Dice of Doom! Holy crap, 28 | ;; four versions of a stupid game?! NOOOO!. I will do something more useful. 29 | 30 | ;; BTW, this shit style to redefining functions and using package of earlier versions is 31 | ;; a absolutely hell. If you wanna write something great, start writing the great thing first. 32 | ;; REDEFINING AND MIXING-UP IS EVIL. 33 | -------------------------------------------------------------------------------- /land-of-lisp/cap4-conditionals.lisp: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; MM""""""""`M 3 | ;; MM mmmmmmmM 4 | ;; M` MMMM 88d8b.d8b. .d8888b. .d8888b. .d8888b. 5 | ;; MM MMMMMMMM 88''88'`88 88' `88 88' `"" Y8ooooo. 6 | ;; MM MMMMMMMM 88 88 88 88. .88 88. ... 88 7 | ;; MM .M dP dP dP `88888P8 '88888P' '88888P' 8 | ;; MMMMMMMMMMMM 9 | ;; 10 | ;; M""MMMMMMMM M""M M""MMMMM""M MM""""""""`M 11 | ;; M MMMMMMMM M M M MMMMM M MM mmmmmmmM 12 | ;; M MMMMMMMM M M M MMMMP M M` MMMM 13 | ;; M MMMMMMMM M M M MMMM' .M MM MMMMMMMM 14 | ;; M MMMMMMMM M M M MMP' .MM MM MMMMMMMM 15 | ;; M M M M M .dMMM MM .M 16 | ;; MMMMMMMMMMM MMMM MMMMMMMMMMM MMMMMMMMMMMM Version 1.0beta27 17 | ;; 18 | ;; http://github.com/overtone/emacs-live 19 | ;; 20 | ;; Hello Manoel, it's lovely to see you again. I do hope that you're 21 | 22 | 23 | ;; if conditions 24 | 25 | ;; returns true 26 | (if '(1) 27 | :true 28 | :false) 29 | 30 | ;; returns true too 31 | (if '() 32 | :false 33 | :true) 34 | 35 | ;; return the length of a list 36 | (defun my-length (list) 37 | "My function personal length. 38 | That is a common docstring in common lisp." 39 | (if list 40 | (1+ (my-length (cdr list))) 41 | 0)) 42 | 43 | (my-length (list 1 2 3 4)) 44 | 45 | ;; the history behind the simmetry of nil and empty lists 46 | (and (equal () nil) (equal '() 'nil)) 47 | ;; the four () disguises 48 | ;; () | nil 49 | ;; '()| 'nil 50 | 51 | ;; the four () disguises 52 | ;; () | nil 53 | ;; '()| 'nil 54 | 55 | ;; 'yup 56 | (if (= (+ 1 2) 3) 57 | 'yup 58 | 'nope) 59 | 60 | ;; 'nope 61 | (if (= (+ 1 2) 4) 62 | 'yupq 63 | 'nope) 64 | 65 | ;; 'the-list-has-stuff-in-it 66 | (if '(1) 67 | 'the-list-has-stuff-in-it 68 | 'the-list-is-empty) 69 | 70 | ;; the-list-is-empty 71 | (if '() 72 | 'the-list-has-stuff-in-it 73 | 'the-list-is-empty) 74 | 75 | (oddp 3) 76 | (evenp 2) 77 | 78 | 79 | (if (oddp 5) 80 | 'odd-number 81 | (/ 1 10)) 82 | 83 | 84 | ;; progn, global variables and the if 'form' (nothing here is statement, all are 'forms') 85 | (defvar *number-was-odd* nil) 86 | 87 | (defun nice-side-effect-lol (x) 88 | "If odd return the symbol correspondent 89 | the side-effect is change the global 90 | variable *number-was-odd*" 91 | (if (oddp x) 92 | (progn (setf *number-was-odd* t) 93 | 'odd-number) 94 | 'even-number)) 95 | 96 | (nice-side-effect-lol 5) *number-was-odd* 97 | 98 | ;; 99 | ;; BASIC IDEAS ABOUT CONDITIONALS 100 | ;; 101 | 102 | (defvar *number-is-odd* nil) 103 | (when (oddp 5) 104 | (setf *number-is-odd* t) 105 | 'odd-number) 106 | 'yup 107 | 'nope) 108 | 109 | (if (= (+ 1 2) 4) 110 | 'yup 111 | 'nope) 112 | 113 | (if '(1) 114 | 'the-list-has-stuff-in-it 115 | 'the-list-is-empty) 116 | 117 | (if '() 118 | 'the-list-has-stuff-in-it 119 | 'the-list-is-empty) 120 | 121 | (if (oddp 5) 122 | 'odd-number 123 | (/ 1 10)) 124 | 125 | 126 | ;; more examples about if form 127 | (defvar *number-was-odd* nil) 128 | 129 | (defun nice-side-effect-lol (x) 130 | (if (oddp x) 131 | (progn (setf *number-was-odd* t) 132 | 'odd-number) 133 | 'even-number)) 134 | 135 | (nice-side-effect-lol 5) 136 | 137 | 138 | ;; 139 | ;; SYMMETRY IF-ELSE: WHEN AND UNLESS 140 | ;; 141 | 142 | 143 | ;; conditiions; 144 | ;; if, when unless command 145 | ;; case, cond or 146 | 147 | ;; if equivalent -> if-else 148 | ;; when -> if block 149 | ;; unless -> if not block 150 | ;; why use when-unless instead if? Because when 151 | ;; don't do nothing in the opposite way 152 | 153 | (defvar *number-is-odd* nil) 154 | (when (oddp 5) 155 | (setf *number-is-odd* t) 156 | 'odd-number) ;; returns odd-number and ste number-is-odd = t 157 | 158 | (unless (oddp 4) 159 | (setf *number-is-odd* nil) 160 | 'even-number) ;; -> even-number set *number-is-odd* = nil 161 | 162 | 163 | ;; 164 | ;; COND AND CASE 165 | ;; 166 | 167 | ;; the command that does it all: cond 168 | ;; the cond form is the classic way 169 | ;; to do branching in lisp 170 | ;; through the liberal use of parentheses, it allow for an implicit progn, 171 | ;; can handle more than one branch, and can even evaluate several conditions 172 | ;; in sucession 173 | ;; many lispers consider the 'cond' is the one true lisp conditional 174 | 175 | (defvar *arch-enemy* nil) 176 | (defun pudding-eater (person) 177 | (cond ((eq person 'henry) (setf *arch-enemy* 'stupid-lisp-alien) 178 | '(curse you lisp alien - you ate my pudding)) 179 | ((eq person 'johnny) (setf *arch-enemy* 'useless-old-johnny) 180 | '(i hope you choked on my pudding johnny ?)) 181 | (t '(why you eat my pudding stranger ?)))) 182 | 183 | 184 | (pudding-eater 'johnny) *arch-enemy* 185 | (pudding-eater 'henery) *arch-enemy* 186 | 187 | ;; as you can see the cond use a body of parentheses conditions to evaluate 188 | ;; a bunch of possible branchs and conditionals 189 | ;; is like of sum of when 190 | ;; now go re-write the pudding-eater function with case! 191 | 192 | 193 | (defun pudding-eater (person) 194 | (case person 195 | ((henry) (setf *arch-enemy* 'stupid-lisp-alien) 196 | '(curse you lisp alien - you ate my pudding)) 197 | ((johnny) (setf *arch-enemy* 'useless-old-johnny) 198 | '(i hope you choked on my pudding johnny ?)) 199 | (otherwise '(why you eat my pudding stranger ?)))) 200 | 201 | ;; as you can se, the cond and case are really similar, but case 202 | ;; differ with one point, doesnt individual form equalities, 203 | ;; you choice the case and compares later in the individual branchs 204 | ;; with it. 205 | 206 | ;; 207 | ;; AND-OR AS IF CONDITIONALS 208 | ;; 209 | 210 | ;; now we think about the obscure use of conditionals using 211 | ;; only booleans expressions like 'and' and 'or'. 212 | 213 | (and (oddp 3) (oddp 5) (oddp 9)) ;=> t 214 | (or (oddp 2) (oddp 0) (oddp 1)) ;=> t 215 | 216 | 217 | ;; if you see that, these operators appears only mathematical boolean operators 218 | ;; and nothing about condinitional evaluation. But we had some interesting thing. 219 | ;; On really, he can be used for conditional behavior! 220 | ;; For instance, here's now a way to set a variable global to t when the number is even. 221 | 222 | (defun crazy-evenp (x) 223 | (let (is-even) 224 | (or (oddp x) (setf is-even t)) ;; HMM, so black magic 225 | is-even)) 226 | 227 | (crazy-evenp 5) ;; -> nil 228 | (crazy-evenp 6) ;; -> T 229 | 230 | 231 | ;; That works because boolean operations are lazy, if doesn't necessary more evaluate the other expressions 232 | ;; so we don't evaluate that! For (crazy-evenp 5) returns nil because (oddp 5) is true, as for 'or' operation 233 | ;; we need only a uniq true value, the (setf is-even t) is not evaluated. We can call that 'shortcut Boolean evaluation' 234 | ;; and lisp use that. 235 | 236 | ;; Considering that the follow expression can be translated: 237 | 238 | (if *file-modified* 239 | (if (ask-user-about-saving) 240 | (save-file))) 241 | 242 | (and *file-modified* (ask-user-about-saving) (save-file)) 243 | 244 | ;; The and evaluate sequencialy the expressions, but for that, 245 | ;; (save-file) needs to returns a t value althoug 246 | ;; that kind of function don't explicit mean that, save-file may return other things. 247 | ;; We have a problem with that and some lispers can be say is not cool. 248 | ;; A third version of that, and a bit more clear, can be: 249 | 250 | (if (and *file-modified* 251 | (ask-user-about-saving)) 252 | (save-file)) 253 | 254 | ;; using functions that return more than just truth value 255 | ;; checking if something inside the list 256 | 257 | (if (member 1 '(4 3 2 1 5)) 258 | 'one-is-in-the-list 259 | 'one-is-not-the-list) ;; -> one-is-in-the-list 260 | 261 | ;; 262 | ;; MEMBER AND FIND-IF 263 | ;; 264 | 265 | ;; nice, the behavior is correct, otherwhise... member have a little non-trivial returns. 266 | ;; what you think member returns? t or nil? No. See: 267 | 268 | (member 1 '(4 3 2 1 5)) ; -> '(1 5) 269 | (member 2 '(4 3 2 1 5)) ; -> '(2 1 5) 270 | (member nil '(4 3 2 1 nil)) ; -> (nil) 271 | 272 | ;; observes... (nil) != nil, '(nil) is a list with contem a nil atom, or empty list. Is like '(()) != '() 273 | 274 | ;; Then 'member' returns nil if not found, right, but if true return more of just 't'. 275 | ;; Return the value found until the tail. Whose really make senses if you remeber the way a list is constructed. 276 | ;; '(4 3 2 1 nil) is equal to (cons 4 (cons 3 (cons 2 (cons 1 (cons nil nil))))) 277 | ;; so if I found 2, is only need return the list itself whose will content the values until the tail. 278 | 279 | ;; If you are asking some about "Why doesn't return the value it found, instead the tail?". Remember the means 280 | ;; of t and nil. T is anything who doesn't is nil. So, check that example: 281 | 282 | (if (member nil '(1 2 3 4 nil)) 283 | 'nil-inside-of-the-list 284 | 'nil-not-found) 285 | ;; if member returns the value found, 'nil' so the if will be false and will return 'nil-not-found' 286 | ;; whose don't make any sense. Instead that, (member nil '(1 2 3 4 nil))-> (nil) 287 | 288 | ;; other functions whose can be beneficit of that kind of result is find-if 289 | ;; (find-if #'lambda list) 290 | (find-if #'oddp '(0 2 3 4 5)) ;-> 3 291 | 292 | ;; whose is something like any() function 293 | 294 | (if (find-if #'oddp '(0 1 2 3 4 5)) 295 | :we-have-an-odd-number 296 | :no-odd-number-found) 297 | 298 | ;; by other hand... if we searching about nil? HMM, think: 299 | 300 | (if (find-if #'null '(1 abacate nil something)) 301 | :we-found-a-nil-value 302 | :no-nil-value-here) ; -> no-nil-value-here 303 | 304 | ;; We have now at disapointment here, because find-if return the first value found 305 | ;; whose is filtered by the function passed. 306 | ;; Unfortunelly, we can't use find-if for if statement in that case. 307 | ;; If find-if was equal to member function maybe will can be. 308 | ;; These kind of small things that make even grown lispers shed had a tear 309 | 310 | 311 | ;; COMPARING STUFF: eq, equal and More... 312 | 313 | ;; We have a lot of comparison functions in common lisp 314 | ;; in which is a kind of thing is not beauty on lisp. 315 | ;; we have, eq, equal, string-equal, equalp, eql... 316 | 317 | ;; Conrad'Rules say: 318 | ;; -> use eq for compare symbols 319 | ;; -> use equal for compare everything else 320 | 321 | ;; eq: symbols 322 | (defparameter *fruit* 'apple) 323 | 324 | (cond ((eq *fruit* 'apple) 'its-an-apple) 325 | (eq *fruit* 'orange) 'its-an-orange) 326 | 327 | ;; equal: anything 328 | 329 | (equal 'banana 'banana) ;; symbols workin, but use eq ever (more fast) 330 | (equal '(1 2 3 4) '(1 2 3 4)) ;; arbitrary lists 331 | (equal '(3 2 1) (cons 3 (cons 2 (cons 1 nil)))) ;; lists constructed in different ways 332 | (equal 4 4) ;. comparison of integers 333 | (equal 4.5 4.5) ;; floats 334 | (equal "abacate" "abacate") ;; strings 335 | (equal #\a #\a) ;; chars 336 | 337 | 338 | ;; eql: symbols, numbers and chars (don't use for strings) 339 | (eql "asdf" "asdf") ; -> nil! 340 | (eql :asdf :asdf) ; -> t 341 | (eql #\n #\n) ; -> t 342 | (eql 4.222225 4.222225) ;-> t 343 | 344 | ;; equalp is like equal but using more abstract comparisons, like 345 | ;; ignoring case for strings and float numbers comparisons 346 | (equalp "MAnoel" "manoel") ;-> t 347 | (equalp 1.0 1) ; -> t 348 | 349 | ;; resume about I wrote in that file 350 | ;; conditionals: if, when, unless, cond, case 351 | ;; black-magic-conditionals: and, or 352 | ;; checkers: member, find-if 353 | ;; comparators: eq, eql, equal, equalp, string-equal, = 354 | -------------------------------------------------------------------------------- /land-of-lisp/cap5-building-a-text-game-engine.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | ;; node (description) 6 | (defparameter *nodes* '((living-room (you are in the living-room. 7 | a wizard is snoring loudly on the couch.)) 8 | (garden (you are in a beatiful garden. 9 | there is a well in front of you.)) 10 | (attic (you are in the attic. 11 | there os a giant welding torch in the corner.)))) 12 | 13 | 14 | ;; (node (edge direction way)) 15 | (defparameter *edges* '((living-room (garden west door) 16 | (attic upstairs ladder)) 17 | (garden (living-room east door)) 18 | (attic (living-room downstairs ladder)))) 19 | 20 | 21 | ;; set of objects 22 | (defparameter *objects* '(whiskey bucket frog chain shit gold)) 23 | 24 | 25 | ;; (object location) 26 | (defparameter *objects-locations* '((whiskey living-room) 27 | (bucket living-room) 28 | (chain garden) 29 | (frog garden) 30 | (shit attic) 31 | (gold attic))) 32 | 33 | 34 | ;; we can put the itens of inventory at *objects-locations* 35 | ;; but i decide is better use *inventory* to split that 36 | ;; and is more easily to handle on the functions about pickup-drop 37 | (defparameter *inventory* nil) 38 | 39 | 40 | ;; that variable handle the actual location of the player 41 | (defparameter *location* 'living-room) 42 | 43 | 44 | ;; commands whose the user can be type at repl 45 | (defparameter *allowed-commands* '(inventory look walk pickup drop help)) 46 | 47 | ;; a lot of tests for running 48 | ;; on the end of that script 49 | (defparameter *tests* '((describe-path '(garden west door)) 50 | (describe-location 'living-room *nodes*) 51 | (describe-paths 'living-room *edges*) 52 | (objects-at 'living-room *objects* *objects-locations*) 53 | (describe-objects 'living-room *objects* *objects-locations*) 54 | (look) 55 | (pickup 'whiskey) 56 | (inventory) 57 | (look) 58 | (drop 'whiskey) 59 | (inventory) 60 | (look) 61 | (drop 'whiskey) 62 | (inventory) 63 | (look) 64 | (walk 'upstairs) 65 | (pickup 'shit) 66 | (pickup 'gold) 67 | (drop 'shit) 68 | (inventory) 69 | (look))) 70 | 71 | 72 | ;; nice, functional! no side-effections 73 | (defun describe-location (location nodes) 74 | "Sucint description of the localation provide 75 | @location -> symbol 76 | @nodes -> association list" 77 | (cadr (assoc location nodes))) 78 | 79 | 80 | ;; functional! no side-effects 81 | (defun describe-path (edge) 82 | "Sucint description of the path to achieve. 83 | @edge -> (neighbor direction way)" 84 | `(there is a ,(caddr edge) going ,(cadr edge) from here.)) 85 | 86 | 87 | ;; functional! no side-effects 88 | (defun describe-paths (location edges) 89 | "General description of the possible edges on each location 90 | @location -> symbol 91 | @edges -> association list of `(node (neighbor direction way))" 92 | (apply #'append (mapcar #'describe-path (cdr (assoc location edges))))) 93 | 94 | 95 | ;; functional! no side-effects 96 | (defun objects-at (loc objs obj-locs) 97 | "Get the objects inside the location 98 | @loc -> location symbol 99 | @objs -> set of objects 100 | @obj-locs -> the list with (object location)" 101 | (labels ((at-loc-p (obj) 102 | (eq (cadr (assoc obj obj-locs)) loc))) 103 | (remove-if-not #'at-loc-p objs))) 104 | 105 | 106 | ;; functional! no side-effects 107 | (defun describe-objects (loc objs obj-loc) 108 | "Describe the objects existent of the location 109 | @loc -> location symbol 110 | @objs -> set of objects 111 | @obj-locs -> the list with (object location) 112 | 113 | That function is a wrapper of objects-at printing 114 | A beautiful description of object on the location." 115 | (labels ((describe-obj (obj) 116 | `(you see a ,obj on the floor.))) 117 | (apply #'append (mapcar #'describe-obj (objects-at loc objs obj-loc))))) 118 | 119 | 120 | ;; i like that, but is not functional 121 | ;; appears don't have side-effects, we don't have a same 122 | ;; output with the same args, because use global variables 123 | (defun look () 124 | "Look function, do a general descriptions of your location. 125 | The location, the paths and objects." 126 | (append (describe-location *location* *nodes*) 127 | (describe-paths *location* *edges*) 128 | (describe-objects *location* *objects* *objects-locations*))) 129 | 130 | 131 | ;; nice function! but not functional 132 | ;; variable globals: *location* *edges* 133 | ;; side-effect: change *location* 134 | (defun walk (direction) 135 | "Try change the actual location moving to direction and 136 | achieve the next scenario if is possible. 137 | @direction -> a symbol as possible move: 'west, 'east', 'north, 'sul" 138 | (let ((next (find direction 139 | (cdr (assoc *location* *edges*)) 140 | :key #'cadr))) 141 | (if next 142 | (progn (setf *location* (car next)) 143 | (look)) 144 | '(you cannot go that way.)))) 145 | 146 | 147 | ;; variable globals: *objects-locations*, *inventory* 148 | ;; side-effect: change *objects-locations*, *inventory* 149 | (defun pickup (object) 150 | "Try get a object at the current scenarion *location* 151 | Store at *inventory* and remove from *objects-location* 152 | remove from *objects* to... (but i don't like that) 153 | *objects* your purpose is a set of all objects on the game 154 | @object -> a symbol" 155 | (cond ((member object 156 | (objects-at *location* *objects* *objects-locations*)) 157 | (progn (setf *objects-locations* 158 | (remove-if 159 | #'(lambda (x) (eq (car x) object)) 160 | *objects-locations*)) 161 | (push object *inventory*)) 162 | `(you are now carrying the ,object)) 163 | (t '(you cannot get that.)))) 164 | 165 | 166 | ;; variable globals: *objects-locations*, *inventory* 167 | ;; side-effect: change *objects-locations*, *inventory* 168 | (defun drop (object) 169 | "Drop a existent object on the invetory at the actual location 170 | @object -> a symbol" 171 | (if (member object *inventory*) 172 | (progn (push (list object *location*) *objects-locations*) 173 | (setf *inventory* (remove object *inventory*)) 174 | `(you dropped ,object at ,*location*)) 175 | `(you do not have ,object on your inventory))) 176 | 177 | 178 | ;; variable globals: *inventory* 179 | (defun inventory () 180 | "Show the inventory at actual carrying items" 181 | (cons 'items- *inventory*)) 182 | 183 | ;; first version: simple 184 | (defun game-repl-noob () ;; useless 185 | (loop (print (eval (read))))) 186 | 187 | ;; wishful thinking 188 | (defun game-repl () 189 | "The game-repl protecting 190 | the user for black magic of 191 | lisp repl" 192 | (let ((cmd (game-read))) 193 | (unless (eq (car cmd) 'quit) 194 | (game-print (game-eval cmd)) 195 | (game-repl)))) 196 | 197 | ;; now we need define: 198 | ;; game-print, game-read, game-eval 199 | 200 | (defun game-read () 201 | "Read an expressions without () from stdin 202 | and return the expression with (). 203 | Example: walk lest -> (walk 'lest)" 204 | (let ((cmd (read-from-string 205 | (concatenate 'string "(" (read-line) ")")))) 206 | (flet ((quote-it (x) 207 | (list 'quote x))) 208 | (cons (car cmd) (mapcar #'quote-it (cdr cmd)))))) 209 | 210 | (defun game-eval (sexp) 211 | "Eval only commands alloweds" 212 | (if (member (car sexp) *allowed-commands*) 213 | (eval sexp) 214 | '(i do not know that command))) 215 | 216 | ;; i need understand better that black magic below 217 | (defun tweak-text (lst caps lit) 218 | "Make a correct captilize in a list of symbols" 219 | (when lst 220 | (let ((item (car lst)) 221 | (rest (cdr lst))) 222 | (cond ((eq item #\space) (cons item (tweak-text rest caps lit))) 223 | ((member item '(#\! #\? #\.)) (cons item (tweak-text rest t lit))) 224 | ((eq item #\") (tweak-text rest caps (not lit))) 225 | (lit (cons item (tweak-text rest nil lit))) 226 | ((or caps lit) (cons (char-upcase item) (tweak-text rest nil lit))) 227 | (t (cons (char-downcase item) (tweak-text rest nil nil))))))) 228 | 229 | (defun game-print (lst) 230 | (princ (coerce (tweak-text (coerce (string-trim "() " 231 | (prin1-to-string lst)) 232 | 'list) 233 | t 234 | nil) 235 | 'string)) 236 | (fresh-line)) 237 | 238 | ;; no side effect 239 | (defun help () 240 | "Show a descriptions of possible commands to interact 241 | with the lisp world." 242 | '(options -> (look) (walk ?direction) (inventory) (pickup ?object) (drop ?object))) 243 | 244 | (defun eval-printing (command) 245 | "The logic behind the scenes is: 246 | Print the command, so eval the command printed 247 | and print the output" 248 | (print (cons 'command-execute-> `(,command))) 249 | (print (cons 'output-of-command-> (eval command)))) 250 | 251 | (defun run-tests (tests) 252 | (mapcar #'eval-printing tests)) 253 | 254 | (defun simple-test () 255 | (princ (princ 'quit))) 256 | -------------------------------------------------------------------------------- /land-of-lisp/cap6-reading-and-printing.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; fundamentals printing 5 | 6 | ;; :: print 7 | ;; print send the arg to sdout with #\newline before the sentence 8 | ;; and add on the end a white-space too LOL something like that: 9 | ;; (format t "~% ~s " 'simbol) ;; realy crazy!!!! 10 | ;; and return the output 11 | (print 'abacate) 12 | (print '(some data)) 13 | (print ':this-is-a-keyword) 14 | (print "that is a string") 15 | 16 | ;; :: prin1 17 | ;; same thing of the 'print' function, but return a space 18 | ;; instead newline 19 | (progn (prin1 "1") 20 | (prin1 "2") 21 | (prin1 "3")) 22 | 23 | ;; simple example combining things 24 | ;; remember: read sucks 25 | ;; read operator only reads a single token. 26 | ;; if you type two tokens will break 27 | (defun say-hello () 28 | (print "Please type your name: ") 29 | (let ((name (read))) 30 | (prin1 "Nice to meet you, ") 31 | (prin1 name))) 32 | (say-hello) 33 | 34 | ;; but print and prin1 is repl stuff, don't cool for humans 35 | ;; print strings with quotes and had a print esoteric behavior of newline-content-space 36 | ;; instead use that, use princ! and read-line 37 | 38 | (progn (princ "An weird way to") 39 | (princ #\newline) 40 | (princ "To split a phrase")) 41 | 42 | (defun say-hello ()q 43 | (princ "Please type your name: ") 44 | (let ((name (read-line))) ;; read-line is nice! 45 | (princ "Nice to meet you, ") 46 | (princ name))) 47 | 48 | ;; other examples for princ 49 | (princ :foo) 50 | (princ 1.2) 51 | (princ "object") 52 | (princ 2/3) 53 | (princ 'symbol) 54 | -------------------------------------------------------------------------------- /land-of-lisp/cap6.5-lambda.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; simple lambda usage with mapcar 5 | (mapcar (lambda (x) (/ x 2)) '(1 2 3 4)) ;; => (1/2 1 3/2 2) 6 | 7 | ;; is equivalent 8 | (defun half (x) 9 | (/ x 2)) 10 | 11 | (mapcar #'half '(1 2 3 4)) 12 | 13 | ;; lambda' are a macro, so your operands are not evaluated first 14 | -------------------------------------------------------------------------------- /land-of-lisp/cap7-beyond-basic-lists.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defpackage :graph-util 5 | (:use :cl) 6 | (:export :graph->png 7 | :ugraph->png 8 | :main)) 9 | 10 | (in-package :graph-util) 11 | 12 | 13 | ;; associative lists 14 | (defparameter *drink-order* '((bill . double-espresso) 15 | (lisa . samll-drip-coffee) 16 | (john . medium-latte))) 17 | 18 | ;; visualizing tree-like data 19 | (defparameter *house* '((walls (mortar (cement) 20 | (water) 21 | (sand)) 22 | (bricks)) 23 | (windows (glass) 24 | (frame) 25 | (curtains) 26 | (roof (shingles) 27 | (chinmey))))) 28 | ;; this is in someway can be hard to visualize the relations of data 29 | 30 | 31 | ;; lets create a graph 32 | (defparameter *wizard-nodes* '((living-room (you are in the living-room. 33 | a wizard is snoring loudly on the couch.)) 34 | (garden (you are in a beatiful garden. 35 | there is a wall in front of you.)) 36 | (attic (you are in the attic. there 37 | is a giant welding torch in the corner.)))) 38 | 39 | (defparameter *wizard-edges* '((living-room (garden west door) 40 | (attic upstairs ladder)) 41 | (garden (living-room east door)) 42 | (attic (living-room downstairs ladder)))) 43 | 44 | 45 | (defparameter *max-label-length* 30) 46 | 47 | ;; * generating the dot information 48 | 49 | 50 | ;; ** converting node identifiers 51 | 52 | (defun dot-name (exp) 53 | (substitute-if #\_ (complement #'alphanumericp) (prin1-to-string exp))) 54 | 55 | 56 | (defun dot-label (exp) 57 | (if exp 58 | (let ((s (write-to-string exp :pretty nil))) ;; :pretty nil avoid modify the original exp 59 | (if (> (length s) *max-label-length*) 60 | (concatenate 'string (subseq s 0 (- *max-label-length* 3)) "...") 61 | s)) 62 | "")) 63 | 64 | 65 | (defun nodes->dot (nodes) 66 | (mapc (lambda (node) 67 | (fresh-line) 68 | (princ (dot-name (car node))) 69 | (princ "[label=\"") 70 | (princ (dot-label node)) 71 | (princ "\"];")) 72 | nodes)) 73 | 74 | 75 | (defun edges->dot (edges) 76 | (mapc (lambda (node) 77 | (mapc (lambda (edge) 78 | (fresh-line) ;; wtf is that? 79 | (princ (dot-name (car node))) 80 | (princ "->") 81 | (princ (dot-name (car edge))) 82 | (princ "[label=\"") 83 | (princ (dot-label (cdr edge))) 84 | (princ "\"];")) 85 | (cdr node))) 86 | edges)) 87 | 88 | 89 | (defun graph->dot (nodes edges) 90 | (princ "digraph{") 91 | (nodes->dot nodes) 92 | (edges->dot edges) 93 | (princ "}")) 94 | 95 | 96 | (defun dot->png (fname thunk) 97 | (with-open-file (*standard-output* 98 | fname 99 | :direction :output 100 | :if-exists :supersede) 101 | (funcall thunk)) 102 | ;; generate graph using fname calling dot 103 | (sb-ext:run-program "dot" (list "-Tpng" "-O" fname) :search t :wait t) 104 | 105 | ;; delete the file 106 | (sb-ext:run-program "rm" (list fname) :search t :wait t)) 107 | 108 | 109 | ;; thunk definition: nullary functions, with zero arguments 110 | ;; can be called suspension too 111 | 112 | 113 | ;; note: symbols with prefixed colon are constants, like => :direction :output and so on 114 | 115 | ;; (let ((:cigar 5)) 116 | ;; :cigar) 117 | ;; => 118 | ;; Compile-time error: 119 | ;; :CIGAR is a keyword, and cannot be used as a local variable. 120 | ;; [Condition of type SB-INT:COMPILED-PROGRAM-ERROR] 121 | 122 | 123 | (defun graph->png (fname nodes edges) 124 | (dot->png fname 125 | (lambda () 126 | (graph->dot nodes edges)))) 127 | 128 | 129 | ;; creating undirected graphs 130 | 131 | (defun uedges->dot (edges) 132 | (maplist (lambda (lst) ;; ? maplist? 133 | (mapc (lambda (edge) 134 | (unless (assoc (car edge) (cdr lst)) 135 | (fresh-line) 136 | (princ (dot-name (caar lst))) 137 | (princ "--") 138 | (princ (dot-name (car edge))) 139 | (princ "[label=\"") 140 | (princ (dot-label (cdr edge))) 141 | (princ "\"];"))) 142 | (cdar lst))) 143 | edges)) 144 | 145 | (defun ugraph->dot (nodes edges) 146 | (princ "graph{") 147 | (nodes->dot nodes) 148 | (uedges->dot edges) 149 | (princ "}")) 150 | 151 | (defun ugraph->png (fname nodes edges) 152 | (dot->png fname 153 | (lambda () 154 | (ugraph->dot nodes edges)))) 155 | 156 | (defun main() 157 | 158 | (in-package :graph-util) 159 | ;; exotic lists 160 | 161 | (cons 1 (cons 2 (cons 3 nil))) 162 | '(1 2 3) 163 | '(1 . (2 . (3 . nil))) 164 | 165 | ;; representations of lists above are equivalents in its implementation 166 | ;; just conses of cells. 167 | 168 | ;; association lists (dotted lists) 169 | (assoc 'lisa *drink-order*) 170 | (push '(lisa . large-mocha-with-whipped-cream) *drink-order*) 171 | (assoc 'lisa *drink-order*) 172 | 173 | ;; circular lists 174 | ;; (let ((foo '(1 2 3))) 175 | ;; (setf (cdddr foo) foo)) ;; circle list!! 176 | 177 | ;; substitute-if higher-order function 178 | (substitute-if 0 #'oddp '(1 2 3 4 5 6 7 8 9 10)) 179 | ;; => (0 2 0 4 0 6 0 8 0 10) 180 | 181 | ;; complement higher-order function 182 | ;; (complement #'oddp) <=> (lambda (x) (not (oddp x))) 183 | 184 | (nodes->dot *wizard-nodes*) 185 | ;; => LIVING_ROOM[label="(LIVING-ROOM (YOU ARE IN TH..."]; 186 | ;; => GARDEN[label="(GARDEN (YOU ARE IN A BEATI..."]; 187 | ;; => ATTIC[label="(ATTIC (YOU ARE IN THE ATTI..."]; 188 | 189 | (dot-label (expt 10 35)) 190 | ;; => "100000000000000000000000000..." 191 | (subseq '(1 2 3 4) 0 2) 192 | ;; => (1 2) 193 | (graph->dot *wizard-nodes* *wizard-edges*) 194 | ;; => 195 | ;; digraph{ 196 | ;; LIVING_ROOM[label="(LIVING-ROOM (YOU ARE IN TH..."]; 197 | ;; GARDEN[label="(GARDEN (YOU ARE IN A BEATI..."]; 198 | ;; ATTIC[label="(ATTIC (YOU ARE IN THE ATTI..."]; 199 | ;; LIVING_ROOM->GARDEN[label="(WEST DOOR)"]; 200 | ;; LIVING_ROOM->ATTIC[label="(UPSTAIRS LADDER)"]; 201 | ;; GARDEN->LIVING_ROOM[label="(EAST DOOR)"]; 202 | ;; ATTIC->LIVING_ROOM[label="(DOWNSTAIRS LADDER)"];} 203 | (edges->dot *wizard-edges*) 204 | ;; => LIVING_ROOM->GARDEN[label="(WEST DOOR)"]; 205 | ;; => LIVING_ROOM->ATTIC[label="(UPSTAIRS LADDER)"]; 206 | ;; => GARDEN->LIVING_ROOM[label="(EAST DOOR)"]; 207 | ;; => ATTIC->LIVING_ROOM[label="(DOWNSTAIRS LADDER)"]; 208 | 209 | ;; writes "Hello File!" into "testfile.txt" 210 | (with-open-file (my-stream 211 | "testfile.txt" 212 | :direction :output ;; ?? 213 | :if-exists :supersede) ;; ?!?!? 214 | (princ "Hello File!" my-stream)) 215 | ;; :direction :output => we're only writing to the file and not reading it 216 | ;; :if-exists :supersede => if a file by that name already exists, just too out the old version 217 | 218 | 219 | (graph->png "wizard-graph.dot" *wizard-nodes* *wizard-edges*) 220 | (ugraph->png "wizard-graph-undirected.dot" 221 | *wizard-nodes* 222 | *wizard-edges*) 223 | 224 | ;; wow, this works! GREAT. 225 | 226 | ;; maplist iterating by cdr 227 | ;; maplist itearting by car 228 | ;; map needs a selector 229 | (mapcar #'print '(a b c)) 230 | ;; => 231 | ;; A 232 | ;; B 233 | ;; C 234 | 235 | (maplist #'print '(a b c)) 236 | ;; => 237 | ;; (A B C) 238 | ;; (B C) 239 | ;; (C) 240 | ) 241 | ;; EOF 242 | -------------------------------------------------------------------------------- /land-of-lisp/cap8-neowumpus.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (load "cap7-beyond-basic-lists") ;; load package on namespace :graph-util 5 | 6 | ;; functions: 7 | ;; (graph-util:ugraph->png 'fname 'nodes 'edges) 8 | ;; (graph-util:graph->png 'fname 'nodes 'edges) 9 | 10 | (defparameter *congestion-city-nodes* nil) 11 | (defparameter *congestion-city-edges* nil) 12 | (defparameter *node-num* 30) 13 | (defparameter *edge-num* 45) 14 | (defparameter *worm-num* 3) 15 | (defparameter *cop-odds* 15) 16 | (defparameter *visited-nodes* nil) 17 | (defparameter *player-pos* nil) 18 | 19 | ;; note: make sure that (random n) generates whole numbers in that range 20 | ;; => [0, n) 21 | (defun random-node () 22 | "Return a random number between 1 and *node-num* (30 for default)" 23 | (1+ (random *node-num*))) 24 | 25 | (defun edge-pair (a b) 26 | "Generate a edge pair given a b nodes. Return nil if a e b is equal symbols." 27 | (unless (eql a b) 28 | (list (cons a b) (cons b a)))) 29 | 30 | (defun make-edge-list () 31 | "Generate a list of edges based on random-nodes" 32 | (apply #'append (loop repeat *edge-num* 33 | collect (edge-pair (random-node) 34 | (random-node))))) 35 | 36 | (defun examples-of-loop-macro () 37 | (loop repeat 10 38 | collect 1) 39 | ;; => (1 1 1 1 1 1 1 1 1 1) 40 | (loop for n from 1 to 10 41 | collect n) 42 | ;; => (1 2 3 4 5 6 7 8 9 10) 43 | (loop for n from 1 to 10 44 | collect (+ 100 n)) 45 | ;; => (101 102 103 104 105 106 107 108 109 110) 46 | ) 47 | 48 | ;; connecting isolated non-connected nodes after (make-edge-list) 49 | ;; generation using random 50 | 51 | ;; get the edges connect with node for another node 52 | (defun direct-edges (node edge-list) 53 | (remove-if-not (lambda (x) 54 | (eql (car x) node)) 55 | edge-list)) 56 | 57 | ;; get the possible nodes to visit starting with this node 58 | (defun get-connected (node edge-list) 59 | (let ((visited nil)) 60 | (labels ((traverse (node) 61 | (unless (member node visited) 62 | (push node visited) 63 | ;; mapc is not destructive (didn't modify data of arguments) 64 | (mapc (lambda (edge) ;; mapc is like a for-each, but return the second argument instead nil 65 | (traverse (cdr edge))) 66 | (direct-edges node edge-list))))) 67 | (traverse node)) 68 | visited)) 69 | 70 | ;; find islands~! unconnected nodes on the edges 71 | (defun find-islands (nodes edge-list) 72 | (let ((islands nil)) 73 | (labels ((find-island (nodes) 74 | (let* ((connected (get-connected (car nodes) edge-list)) 75 | (unconnected (set-difference nodes connected))) ;; difference between two lists A - B 76 | (push connected islands) 77 | (when unconnected 78 | (find-island unconnected))))) 79 | (find-island nodes)) 80 | islands)) 81 | 82 | 83 | ;; create edges for isolated group of nodes (islands) 84 | (defun connect-with-bridges (islands) 85 | (when (cdr islands) 86 | (append (edge-pair (caar islands) (caadr islands)) 87 | (connect-with-bridges (cdr islands))))) 88 | 89 | ;; create edges for all isolated group of nodes 90 | (defun connect-all-islands (nodes edge-list) 91 | (append (connect-with-bridges (find-islands nodes edge-list)) 92 | edge-list)) 93 | 94 | 95 | (defun add-cops (edge-alist edges-with-cops) 96 | (mapcar (lambda (x) 97 | (let ((node1 (car x)) 98 | (node1-edges (cdr x))) 99 | (cons node1 100 | (mapcar (lambda (edge) 101 | (let ((node2 (car edge))) 102 | (if (intersection (edge-pair node1 node2) 103 | edges-with-cops 104 | :test #'equal) 105 | (list node2 'cops) 106 | edge))) 107 | node1-edges)))) 108 | edge-alist)) 109 | 110 | (defun edges-to-alist (edge-list) 111 | (mapcar (lambda (node1) 112 | (cons node1 113 | (mapcar (lambda (edge) 114 | (list (cdr edge))) 115 | (remove-duplicates (direct-edges node1 edge-list) 116 | :test #'equal)))) 117 | (remove-duplicates (mapcar #'car edge-list)))) 118 | 119 | 120 | (defun make-city-edges() 121 | (let* ((nodes (loop for i from 1 to *node-num* collect i)) 122 | (edge-list (connect-all-islands nodes (make-edge-list))) 123 | (cops (remove-if-not (lambda (x) 124 | (declare (ignore x)) ;; SBCL stuff, avoid warning 125 | (zerop (random *cop-odds*))) 126 | edge-list))) 127 | (add-cops (edges-to-alist edge-list) cops))) 128 | 129 | ;; selectors 130 | 131 | (defun neighbors (node edge-alist) 132 | (mapcar #'car (cdr (assoc node edge-alist)))) 133 | 134 | (defun within-one (a b edge-alist) 135 | (member b (neighbors a edge-alist))) 136 | 137 | (defun within-two (a b edge-list) 138 | (or (within-one a b edge-list) 139 | (some (lambda (x) 140 | (within-one x b edge-list)) 141 | (neighbors a edge-list)))) 142 | 143 | (defun make-city-nodes (edge-alist) 144 | (let ((wumpus (random-node)) 145 | (glow-worms (loop for i below *worm-num* 146 | collect (random-node)))) 147 | (loop for n from 1 to *node-num* 148 | collect (append (list n) 149 | (cond ((eql n wumpus) '(wumpus)) 150 | ((within-two n wumpus edge-alist) '(blood!))) 151 | (cond ((member n glow-worms) 152 | '(glow-worm)) 153 | ((some (lambda (worm) 154 | (within-one n worm edge-alist)) 155 | glow-worms) 156 | '(lights!))) 157 | (when (some #'cdr (cdr (assoc n edge-alist))) 158 | '(sirens!)))))) 159 | 160 | (defun find-empty-node () 161 | (let ((x (random-node))) 162 | (if (cdr (assoc x *congestion-city-nodes*)) 163 | (find-empty-node) 164 | x))) 165 | 166 | (defun draw-city () 167 | (graph-util:ugraph->png "city" *congestion-city-nodes* *congestion-city-edges*)) 168 | 169 | 170 | ;; BUG FOUND HERE!!! 171 | (defun known-city-nodes () 172 | (mapcar (lambda (node) 173 | (if (member node *visited-nodes*) 174 | (let ((n (assoc node *congestion-city-nodes*))) 175 | (if (eql node *player-pos*) 176 | (append n '(*)) 177 | n)) 178 | (list node '? ))) 179 | (remove-duplicates 180 | (append *visited-nodes* 181 | (mapcan (lambda (node) 182 | (mapcar #'car (cdr (assoc node *congestion-city-edges*)))) 183 | *visited-nodes*))))) 184 | 185 | 186 | (defun known-city-edges () 187 | (mapcar (lambda (node) 188 | (cons node (mapcar (lambda (x) 189 | (if (member (car x) *visited-nodes*) 190 | x 191 | (list (car x)))) 192 | (cdr (assoc node *congestion-city-edges*))))) 193 | *visited-nodes*)) 194 | 195 | (defun example-mapcan-function () 196 | (labels ((ingredients (order) 197 | (mapcan (lambda (burger) 198 | (case burger 199 | (single '(patty)) 200 | (double '(patty patty)) 201 | (double-cheese '(patty patty cheese)))) 202 | order))) 203 | (ingredients '(single double-cheese double)))) 204 | ;; => (PATTY PATTY PATTY CHEESE PATTY PATTY) 205 | 206 | 207 | (defun draw-known-city () 208 | (graph-util:ugraph->png "known-city" (known-city-nodes) (known-city-edges))) 209 | 210 | 211 | (defun new-game () 212 | (setf *congestion-city-edges* (make-city-edges)) 213 | (setf *congestion-city-nodes* (make-city-nodes *congestion-city-edges*)) 214 | (setf *player-pos* (find-empty-node)) 215 | (setf *visited-nodes* (list *player-pos*)) 216 | (draw-city) 217 | (draw-known-city)) 218 | 219 | ;; some bug was tracked here 220 | ;; EDITED: actually is in known-city-nodes 221 | ;; backtrace: handle-new-place -> draw-known-city -> known-city-nodes 222 | (defun handle-new-place (edge pos charging) 223 | (let* ((node (assoc pos *congestion-city-nodes*)) 224 | (has-worm (and (member 'glow-worm node) 225 | (not (member pos *visited-nodes*))))) 226 | (pushnew pos *visited-nodes*) 227 | (setf *player-pos* pos) 228 | (draw-known-city) 229 | (cond ((member 'cops edge) (princ "You ran into the cops. Game Over!")) 230 | ((member 'wumpus node) (if charging 231 | (princ "You found the Wumpus!") 232 | (princ "You ran into the Wumpus"))) 233 | (charging (princ "You wasted your last bullet. Game Over!")) 234 | (has-worm (let ((new-pos (random-node))) 235 | (princ "You ran into a Glow Worm Gang! You're now at ") 236 | (princ new-pos) 237 | (handle-new-place nil new-pos nil)))))) 238 | 239 | (defun handle-direction (pos charging) 240 | (let ((edge (assoc pos 241 | (cdr (assoc *player-pos* *congestion-city-edges*))))) 242 | (if edge 243 | (handle-new-place edge pos charging) 244 | (princ "That location does not exist!")))) 245 | 246 | (defun walk (pos) 247 | (handle-direction pos nil)) 248 | 249 | (defun charge (pos) 250 | (handle-direction pos t)) 251 | 252 | ;; HOW TO PLAY:: 253 | ;; (load "this-file") 254 | ;; (new-game) 255 | ;; => created a file called known-city.png 256 | ;; => so well the, for spoilers, an overall map of the city is created as city.png 257 | ;; open it in a browser, it's our map 258 | ;; use (walk num) & (charge num) to walk and shot between the nodes from edges 259 | ;; at each walk/charge call a new known-city.png is generated (updated) 260 | ;; you have just one shot, so make sure to not waste this bullet 261 | -------------------------------------------------------------------------------- /land-of-lisp/cap9-advanced-generic-programming.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; advanced datatypes: 5 | ;; + ARRAY 6 | ;; + HASH-TABLES 7 | ;; + STRINGS 8 | ;; + STRUCTURES 9 | 10 | ;; generic functions: 11 | ;; sequence functions: 12 | ;; + REDUCE 13 | ;; + FIND-IF 14 | ;; + SOME 15 | ;; + EVERY 16 | ;; + POSITION 17 | ;; + COUNT 18 | ;; generic setter: 19 | ;; + SETF 20 | 21 | ;; best way to handle various datatypes: DEFMETHOD 22 | 23 | (defparameter examples nil) 24 | 25 | (defmacro define-example (name &rest body) 26 | `(push (cons (quote ,name) 27 | (apply #'list (quote ,body))) examples)) 28 | 29 | (define-example example-of-arrays 30 | (make-array 3) 31 | ;; => #(0 0 0) 32 | (defparameter x (make-array 3)) 33 | ;; x => #(0 0 0) 34 | (aref x 1) ;; => 0 35 | 36 | ;; the generic setf macro operator 37 | (setf (aref x 1) 'foo) 38 | ;; x => #(0 FOO 0) 39 | ;; combining setf + aref we can set elements on 40 | ;; array positions 41 | 42 | ;; but this can be used in list too! 43 | ;; yes... lists of common lisp is not immutable! 44 | ;; functional programming? forget about that. 45 | 46 | (defparameter foo '(a b c)) 47 | foo 48 | ;; foo => (a b c) 49 | (second foo) 50 | ;; => B 51 | (setf (second foo) 'z) 52 | foo 53 | ;; => (a z c) 54 | 55 | ;; setf is a magic setter. 56 | (defparameter foo (make-array 4)) 57 | foo 58 | ;; => #(0 0 0 0) 59 | 60 | (setf (aref foo 2) '(x y z)) 61 | foo 62 | ;; => #(0 0 (X Y Z) 0) 63 | 64 | (setf (car (aref foo 2)) (make-hash-table)) 65 | ;; hash tables has its own examples in the next section 66 | 67 | (setf (gethash 'zoink (car (aref foo 2))) 5) 68 | foo 69 | ;; => #(0 0 (# Y Z) 0) 70 | ) 71 | 72 | (define-example array-vs-lists 73 | (nth 1 '(foo bar baz)) 74 | ;; access O(n) 75 | 76 | (aref #(foo bar baz) 1) 77 | ;; access O(1) 78 | 79 | ;; tl;dr => array has a better performance than lists 80 | 81 | ) 82 | 83 | 84 | ;; hash tables are like alists (assoc lists) => ((key value) ... ... ... (key-n value-n)) 85 | (define-example example-of-hash-tables 86 | ;; create a new hash table 87 | (make-hash-table) 88 | ;; => # 89 | (defparameter x (make-hash-table)) 90 | (gethash 'yup x) 91 | ;; => NIL, NIL 92 | (setf (gethash 'yup x) '25) 93 | (gethash 'yup x) 94 | ;; => 25, T 95 | 96 | ;; defining drink-order example like alist made before 97 | (defparameter *drink-order* (make-hash-table)) 98 | (setf (gethash 'bill *drink-order*) 'double-espresso) 99 | (setf (gethash 'lisa *drink-order*) 'small-drip-coffee) 100 | (setf (gethash 'john *drink-order*) 'medium-latte) 101 | 102 | ;; accessing the drink order for any person 103 | (gethash 'lisa *drink-order*) 104 | ;; hash table access performance is like array 105 | ;; access/set time -> O(1) 106 | ) 107 | 108 | (define-example returning-multiple-values 109 | (round 2.4) 110 | ;; => 2, 0.4 111 | (defun foo () (values 3 7)) 112 | (foo) 113 | ;; => 3, 7 114 | (+ (foo) 5) 115 | ;; => 8 (ignoring the second value) 116 | 117 | ;; bind multiple values from functions and create 118 | ;; a lexical scope like let 119 | (multiple-value-bind (a b) (foo) 120 | (+ a b)) 121 | ;; => 10 122 | 123 | ;; the usage of multiple-values is supported by CL 124 | ;; but is not so common used on moderns lisp dialects 125 | ;; like clojure 126 | 127 | ;; BTW, Land of Lisp explicitly say that on this book 128 | ;; we don't will see much examples of this. 129 | 130 | ;; I don't have sure if this is really useful. 131 | ;; Maybe passing error state like Go (value error) 132 | ) 133 | 134 | (define-example example-of-structures 135 | (defstruct person 136 | :name 137 | :age 138 | :waist-size 139 | :favorite-color) ;; 4 slots 140 | (defparameter *bob* (make-person :name "Bob" 141 | :age 35 142 | :waist-size 32 143 | :favorite-color "blue")) 144 | *bob* 145 | ;; => #S(PERSON :NAME "Bob" :AGE 35 :WAIST-SIZE 32 :FAVORITE-COLOR "blue") 146 | (person-age *bob*) 147 | ;; => 35 148 | (setf (person-age *bob*) 36) ;; the magic setter macro again 149 | ;; works fine with structures as well 150 | (person-age *bob*) 151 | ;; => 36 152 | 153 | 154 | ;; the problem of lispers and object-oriented programming 155 | ;; let's see a alternative for structures only using lists 156 | (defun make-person. (name age waist-size favorite-color) 157 | (list name age waist-size favorite-color)) 158 | (defun person-age. (person) 159 | (cadr person)) 160 | (defparameter *bob* (make-person. "bob" 35 32 "blue")) 161 | *bob* 162 | (person-age. *bob*) 163 | 164 | ;; but is a bad idea. we'll need all the selectors for person 165 | ;; and the REPL representation is useless. How we can say if 166 | ;; this list define a person. Bob's age is 35 or 32? 167 | ;; Another problem is changing the state... lists don't works well 168 | ;; with it. First: your nature is a bunch of recursive cons cells. 169 | ;; In that example the better approach is defining structures in CL. 170 | 171 | ) 172 | 173 | 174 | (define-example example-handling-data-in-a-generic-way 175 | ;; a great example of generic function 176 | ;; at which can handle various types is the 177 | ;; function length 178 | ;; that type of functions are called of: 179 | ;; "sequence functions" (handle sequences) 180 | (length "blub") 181 | ;; => 4 182 | (length '(a b c)) 183 | ;; => 3 184 | (length (make-array 5)) 185 | ;; => 5 186 | 187 | ;; another great examples for sequence functions 188 | ;; are the specific for search: 189 | ;; find-if, count, position, some and every 190 | 191 | (find-if #'numberp '(a b 5 d)) 192 | ;; => 5 193 | (count #\s "Mississippi") 194 | ;; => 4 195 | (position #\4 "2kewl4skewl") 196 | ;; => 5 197 | (some #'numberp '(a b 5 d)) 198 | ;; => T 199 | (every #'numberp '(a b 5 d)) 200 | ;; => NIL 201 | 202 | ;; another useful generic sequence function: reduce 203 | (reduce #'+ '(3 4 6 5 2)) 204 | ;; => 20 205 | ;; an way to understand the evaluation of reduce is 206 | (reduce #'cons '(1 2 3 4)) 207 | ;; => (((1 . 2) . 3) . 4) 208 | (reduce (lambda (best item) 209 | (if (and (evenp item) 210 | (> item best)) 211 | item 212 | best)) 213 | '(7 4 6 5 2) 214 | :initial-value 0) 215 | ;; => 6 216 | ;; without define the initial-value we got 7 217 | 218 | 219 | (defun sum (sequence) 220 | (reduce #'+ sequence)) 221 | 222 | (sum '(1 2 3)) 223 | (sum #(1 2 3 4 5)) 224 | 225 | (map 'string 226 | (lambda (x) 227 | (if (eq x #\s) 228 | #\S 229 | x)) 230 | "this is a string") 231 | 232 | ;; two more import sequence functions: subseq and 233 | ;; sort 234 | 235 | (subseq "america" 2 6) 236 | ;; => eric 237 | (sort '(5 8 2 4 9 3 6) #'<) 238 | ;; => (2 3 4 5 6 8 9) 239 | 240 | ;; we can create our own generic functions 241 | ;; using typing checking; the most frequently 242 | ;; predicates are: arrayp, characterp, consp, 243 | ;; hash-table-p, listp, stringp, symbolp 244 | 245 | (defun add (a b) 246 | (cond ((and (numberp a) 247 | (numberp b)) 248 | (+ a b)) 249 | ((and (listp a) 250 | (listp b)) 251 | (append a b)))) 252 | 253 | (add 1 2) 254 | ;; => 3 255 | (add '(1 2) '(3 4)) 256 | ;; => (1 2 3 4) 257 | 258 | ;; but we have a better way to do this using 259 | ;; generic methods for multiple types 260 | ;; this is called "type dispatching" 261 | 262 | (defmethod add. ((a number) (b number)) 263 | (+ a b)) 264 | 265 | (defmethod add. ((a list) (b list)) 266 | (append a b)) 267 | 268 | (add. 1 2) 269 | (add. '(a b) '(c d)) 270 | 271 | 272 | ;; the `defmethod` is like `defun` except that it 273 | ;; allows us to write multiple functions with 274 | ;; the same name 275 | 276 | ;; defstruct + defmethod => simple OO system 277 | ) 278 | 279 | 280 | (defun print-example (example) 281 | (let ((name (car example)) 282 | (instrunctions (cdr example))) 283 | (format t ":: ~A ~%" name) 284 | (loop for i in instrunctions do 285 | (format t "> ~a~%~a~%" i (eval i))) 286 | (princ #\newline))) 287 | 288 | (defun run-examples () 289 | (mapcar #'print-example (reverse examples))) 290 | 291 | 292 | ;; the continuation of this chapter is a game called: 293 | ;; ORC BATTLE GAME 294 | ;; I'll write the functions in another file because 295 | ;; this is especial of only REPL examples at which 296 | ;; I use the define-example macro to can be executable 297 | 298 | 299 | (run-examples) 300 | -------------------------------------------------------------------------------- /land-of-lisp/cap9-orc-battle-game.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | #| 6 | 7 | -- ORC BATTLE GAME -- 8 | 9 | In the Orc Battle game, you are a knight surrounded by 12 monsters, engaged 10 | in a fight to the death. With your superior wits and your repertoire 11 | of sword-fighting maneuvers, you must carefully make strategies in your battle with orcs, 12 | hydras, and other nasty enemies. 13 | 14 | c 15 | Using DEFMETHOD and DEFSTRUCT, let's dispatch some whoop ass on these vermin! 16 | 17 | |# 18 | 19 | 20 | ;; global variables for player status 21 | 22 | (defparameter *player-health* nil) 23 | (defparameter *player-agility* nil) 24 | (defparameter *player-strength* nil) 25 | 26 | 27 | ;; we'll store our monsters in an array called *monsters* 28 | ;; we'll also define a list of functions for building monsters that 29 | ;; we'll store in the variable *monster-builders* (AQUI É MONSTRO, PORRA) 30 | 31 | (defparameter *monsters* nil) 32 | (defparameter *monster-builders* nil) 33 | (defparameter *monster-num* 6) ;; high => more difficult 34 | 35 | (defun randval (n) 36 | (1+ (random (max 1 n)))) 37 | 38 | ;; STRUCTS 39 | 40 | ;; THE MONSTERS 41 | 42 | ;; generic monster strict 43 | (defstruct monster (health (randval 10))) 44 | 45 | ;; THE WICKED ORC 46 | (defstruct (orc (:include monster)) 47 | (club-level (randval 8))) 48 | (push #'make-orc *monster-builders*) 49 | 50 | (defmethod monster-show ((m orc)) 51 | (princ "A wicked orc with a level ") 52 | (princ (orc-club-level m)) 53 | (princ " club")) 54 | 55 | (defmethod monster-attack ((m orc)) 56 | (let ((x (randval (orc-club-level m)))) 57 | (princ "An orc swings his club at you knocks off ") 58 | (princ x) 59 | (princ " of your health points. ") 60 | (decf *player-health* x))) 61 | 62 | 63 | ;; THE MALICIOUS HYDRA 64 | (defstruct (hydra (:include monster))) 65 | (push #'make-hydra *monster-builders*) 66 | 67 | (defmethod monster-show ((m hydra)) 68 | (princ "A malicious hydra with ") 69 | (princ (monster-health m)) 70 | (princ " heads. ")) 71 | 72 | (defmethod monster-hit ((m hydra) x) 73 | (decf (monster-health m) x) 74 | (if (monster-dead m) 75 | (princ "The corpse of the fully decapitated hydra falls to the floor! ") 76 | (progn (princ "You lop off ") 77 | (princ x) 78 | (princ " of hydra's heads! ")))) 79 | 80 | (defmethod monster-attack ((m hydra)) 81 | (let ((x (randval (ash (monster-health m) -1)))) 82 | (princ "A hydra attacks you with ") 83 | (princ x) 84 | (princ " of its heads! It also grows back one more head! ") 85 | (incf (monster-health m)) 86 | (decf *player-health* x))) 87 | 88 | (defstruct (slime-mold (:include monster)) 89 | (slimeness (randval 5))) 90 | (push #'make-slime-mold *monster-builders*) 91 | 92 | 93 | (defmethod monster-attack ((m slime-mold)) 94 | (princ "A slime mold of slimness of ") 95 | (princ (slime-mold-slimeness m)) 96 | (princ " attacks ")) 97 | 98 | (defmethod monster-show ((m slime-mold)) 99 | (let ((x (randval (slime-mold-slimeness m)))) 100 | (princ "A slime mold wraps around your legs and decreases your agility by ") 101 | (princ x) 102 | (princ "! ") 103 | (decf *player-agility* x) 104 | (when (zerop (random 2)) 105 | (princ "It also squirts in your face, taking away a health point! ") 106 | (decf *player-health*)))) 107 | 108 | (defstruct (brigand (:include monster))) 109 | (push #'make-brigand *monster-builders*) 110 | 111 | (defmethod monster-attack ((m brigand)) 112 | (let ((x (max *player-health* 113 | *player-agility* 114 | *player-strength*))) 115 | (cond ((= x *player-health*) 116 | (princ "A brigand hits you with his slingshot taking off 2 health points! ") 117 | (decf *player-health* 2)) 118 | ((= x *player-agility*) 119 | (princ "A brigand catches your leg with his whip taking off 2 agility points! ") 120 | (decf *player-agility* 2)) 121 | ((= x *player-strength*) 122 | (princ "A brigand cuts your arm with his whip, taking off 2 strength points! ") 123 | (decf *player-strength* 2))))) 124 | 125 | 126 | (defun monster-dead (m) 127 | (<= (monster-health m) 0)) 128 | 129 | (defun monsters-dead () 130 | (every #'monster-dead *monsters*)) 131 | 132 | (defmethod monster-hit (m x) 133 | (decf (monster-health m) x) 134 | (if (monster-dead m) 135 | (progn (princ "You killed the ") 136 | (princ (type-of m)) 137 | (princ "! ")) 138 | (progn (princ "You hit the ") 139 | (princ (type-of m)) 140 | (princ ", knocking off") 141 | (princ x) 142 | (princ " health points! ")))) 143 | 144 | 145 | 146 | (defmethod monster-show (m) 147 | (princ "A fierce ") 148 | (princ (type-of m))) 149 | 150 | (defmethod monster-attack (m)) 151 | 152 | ;; helper functions for player attack 153 | (defun random-monster () 154 | (let ((m (aref *monsters* (random (length *monsters*))))) 155 | (if (monster-dead m) 156 | (random-monster) 157 | m))) 158 | 159 | (defun pick-monster () 160 | (fresh-line) 161 | (princ "Monster #:") 162 | (fresh-line) 163 | (let ((x (read))) 164 | (if (not (and (integerp x) 165 | (>= x 1) 166 | (<= x *monster-num*))) 167 | (progn (princ "That is not a valid monster number.") 168 | (pick-monster)) 169 | (let ((m (aref *monsters* (1- x)))) 170 | (if (monster-dead m) 171 | (progn (princ "That monster is already dead.") 172 | (pick-monster)) 173 | m))))) 174 | 175 | (defun init-monsters () 176 | (setf *monsters* 177 | (map 'vector 178 | (lambda (x) 179 | (declare (ignore x)) 180 | (funcall (nth (random (length *monster-builders*)) 181 | *monster-builders*))) 182 | (make-array *monster-num*)))) 183 | 184 | (defun show-monsters () 185 | (fresh-line) 186 | (princ "Your foes:") 187 | (let ((x 0)) 188 | (map 'list 189 | (lambda (m) 190 | (fresh-line) 191 | (princ " ") 192 | (princ (incf x)) 193 | (princ ". ") 194 | (if (monster-dead m) 195 | (princ "**dead**") 196 | (progn (princ "(Health=") 197 | (princ (monster-health m)) 198 | (princ ") ") 199 | (monster-show m)))) 200 | *monsters*))) 201 | 202 | (defun init-player() 203 | "Set the initial tributes of our knight" 204 | (setf *player-health* 30) 205 | (setf *player-agility* 30) 206 | (setf *player-strength* 30)) 207 | 208 | (defun player-dead () 209 | "Check if the player is alive" 210 | (<= *player-health* 0)) 211 | 212 | (defun show-player () 213 | "If the player is alive, show in REPL your info at each action" 214 | (fresh-line) 215 | (format t "You are a valiant knight with a health of ~a, an agility of ~a and a strength of ~a" 216 | *player-health* 217 | *player-agility* 218 | *player-health*)) 219 | 220 | (defun player-attack () 221 | "The player-attack function lets us manage a player's attack" 222 | (fresh-line) 223 | (princ "Attack style: [s]tab [d]ouble swing [r]oundhouse: ") 224 | (fresh-line) 225 | (case (read) 226 | (s (monster-hit (pick-monster) 227 | (+ 2 (randval (ash *player-strength* -1))))) 228 | (d (let ((x (randval (truncate (/ *player-strength* 6))))) 229 | (format t "Your double swing has a strength of ~a" x) 230 | (fresh-line) 231 | (monster-hit (pick-monster) x) 232 | (unless (monsters-dead) 233 | (monster-hit (pick-monster) x)))) 234 | (otherwise (dotimes (x (1+ (randval (truncate (/ *player-strength* 3))))) 235 | (unless (monsters-dead) 236 | (monster-hit (random-monster) 1)))))) 237 | 238 | 239 | 240 | (defun game-loop () 241 | "The game-loop function handles the repeated cycles of monster 242 | and player attacks." 243 | (unless (or (player-dead) 244 | (monsters-dead)) 245 | (fresh-line) 246 | (show-player) 247 | (dotimes (k (1+ (truncate (/ (max 0 *player-agility*) 15)))) 248 | (unless (monsters-dead) 249 | (show-monsters) 250 | (player-attack))) 251 | (fresh-line) 252 | (map 'list 253 | (lambda (m) 254 | (or (monster-dead m) 255 | (monster-attack m))) 256 | *monsters*) 257 | (game-loop))) 258 | 259 | ;; the big picture function 260 | (defun orc-battle () 261 | "Main function of the game" 262 | (init-monsters) 263 | (init-player) 264 | (game-loop) 265 | (when (player-dead) 266 | (princ "You have been killed. Game Over.")) 267 | (when (monsters-dead) 268 | (princ "Congratulations! You have vanquished all of your foes."))) 269 | 270 | 271 | 272 | (orc-battle) 273 | ;; just execute this game via terminal as: sbcl --script this-file-name.lisp 274 | -------------------------------------------------------------------------------- /land-of-lisp/city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryukinix/lisp-insights/626ac715d6632c77a1501a71728336727c8e45d4/land-of-lisp/city.png -------------------------------------------------------------------------------- /land-of-lisp/example.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /land-of-lisp/known-city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryukinix/lisp-insights/626ac715d6632c77a1501a71728336727c8e45d4/land-of-lisp/known-city.png -------------------------------------------------------------------------------- /land-of-lisp/wizard-graph-undirected.dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryukinix/lisp-insights/626ac715d6632c77a1501a71728336727c8e45d4/land-of-lisp/wizard-graph-undirected.dot.png -------------------------------------------------------------------------------- /land-of-lisp/wizard-graph.dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryukinix/lisp-insights/626ac715d6632c77a1501a71728336727c8e45d4/land-of-lisp/wizard-graph.dot.png -------------------------------------------------------------------------------- /mit-6.001/10A-compilation.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | #| 6 | Compilation 7 | 8 | The first strategy for compilation is the zeroth order compilation. That claims in these simple procedures: 9 | 10 | - interpret the code for register machine 11 | - instead execute that, save. 12 | 13 | Done. No optimizations here. 14 | But interpreter is dumb, it is very pessimistic because anything can happens. 15 | By other hand, compilers know what is necessary or no (well, it can know). 16 | 17 | A lot of stack is used during interpretation, but sometimes is useless. 18 | 19 | More details of this lecture is on the Chapter 5 of Structure Interpretation of Computer Programs Book Ed2. 20 | |# 21 | 22 | (defmacro define-compilation (name &rest code) 23 | `(defparameter ,name (quote ,code))) 24 | 25 | ;; a general view of a compilation of (op a b) 26 | (define-compilation op-a-b 27 | (preserves env) 28 | (compile op) 29 | (result in fun) 30 | (preserves fun) 31 | (preserves env) 32 | (compile a) 33 | (assign argl (cons (fetch val) nil)) 34 | (result in val) 35 | (preservs argl) 36 | (compile b) 37 | (result in val) 38 | (assign argl (cons (fetch val) (fetch argl))) 39 | (goto apply-dispatch)) 40 | 41 | ;; treating assignments and using the stack 42 | ;; to preserve registers 43 | 44 | ;; ===:: APPENDING SEQUENCE OF CODES ::== 45 | ;; append seq1 and seq2 preserving reg 46 | 47 | ;; if seq2 needs reg 48 | ;; and seq1 modifies reg 49 | ;;; :: CODE 50 | ;; (save reg) 51 | ;; 52 | ;; (restore reg) 53 | ;; 54 | ;; OTHERWISE 55 | ;;; :: CODE 56 | ;; 57 | ;; 58 | 59 | 60 | ;; sequences of instructions need be tagged about 61 | ;; the registers will be modified 62 | ;; and the registers needed 63 | 64 | ;; this is the general notation of code tagging about 65 | ;; registers modified and needed 66 | (define-compilation template-for-tagging 67 | < sequence of instrunctions > 68 | < set of registers modified > 69 | < set of regs needed >) 70 | 71 | ;; lets compile a factorial function recursive 72 | 73 | (defun fact (n) 74 | (cond ((= n 0) 1) 75 | (t (* n (fact (1- n)))))) 76 | 77 | 78 | (define-compilation fact-compiled 79 | entry1 ;; label 80 | (assign env (compiled-procedure-env (fetch fun))) 81 | (assign env (extended-binding-env '(n) 82 | (fetch argl) 83 | (fetch env))) 84 | (save env) ;; preserving env, will modify in sequence 85 | (assign fun (lookup-variable-value '* (fetch env))) 86 | (assign val (lookup-variable-value 'n (fetch env))) 87 | (assign argl (cons (fetch val) '())) 88 | (assign val '0) 89 | (assign argl (cons (fetch val) (fetch argl))) ;; append argl 90 | (assign continue after-call3) 91 | (goto apply-dispatch) 92 | 93 | after-call3 ;; label 94 | (restore env) 95 | (branch (true? (fetch val)) true-branch2) 96 | (assign fun (lookup-variable-value '* (fetch env))) 97 | (save fun) 98 | (assign val (lookup-variable-value 'm (fetch env))) 99 | (assign argl (cons (fetch val) '())) 100 | (save argl) 101 | (assign fun (lookup-variable-value 'fact (fetch env))) 102 | (save fun) 103 | (assign fun (lookup-variable-value '- (fetch env))) 104 | (assign val (lookup-variable-value 'n (fetch env))) 105 | (assign argl (cons (fetch val)) '()) 106 | (assign val '1) 107 | (assign argl (cons (fetch val (fetch argl)))) 108 | (assign continue after-call5) 109 | (save continue) 110 | (goto apply-dispatch) 111 | 112 | after-call5 ;; label 113 | (assign argl (cons (fetch val) '())) 114 | (restore fun) 115 | (assign continue after-call4) 116 | (save continue) 117 | (goto apply-dispatch) 118 | 119 | after-call4 ;; label 120 | (restore argl) 121 | (assign argl (cons (fetch val) (fetch argl))) 122 | (restore fun) 123 | (goto apply-dispatch) 124 | 125 | true-branch2 126 | (assign val '1) 127 | (restore continue) 128 | (goto (fetch continue))) 129 | -------------------------------------------------------------------------------- /mit-6.001/10B-storage-allocation-and-garbage-collector.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | ;; Storage Allocation and Garbage Collector 6 | ;; Representing Memory List Structure 7 | 8 | ;; ... again register machines. This is a lot of mess. 9 | 10 | ;; Godel says that any system information can be represented by numbers in that way: 11 | ;; (cons x y) => 2^x * 3^y, so (cons 1 1) => 2 * 3 = 6 12 | 13 | (defmacro define-assembly (name &rest instructions) 14 | `(defparameter ,name (quote ,instructions))) 15 | 16 | 17 | (define-assembly freelist-allocation 18 | (assign a (cons (fetch b) 19 | (fetch c))) 20 | (assign a (fetch free)) 21 | (assign free (vector-ref (fetch the-cdrs) 22 | (fetch free))) 23 | (perform (vector-set! (fetch the-cars) 24 | (fetch a) 25 | (fetch b))) 26 | (perform (vector-set! (fetch the-cdrs) 27 | (fetch a) 28 | (fetch c)))) 29 | 30 | 31 | ;; garbage collector 32 | (define-assembly gc-code 33 | gc 34 | (assign thing (fetch root)) 35 | (assign continue) 36 | mark 37 | (branch (not-pair? (fetch thing)) 38 | done) 39 | pair 40 | (assign mark-flag 41 | (vector-ref (fetch the-marks) 42 | (fetch thing))) 43 | (branch (= (fetch mark-flag) 1) 44 | done) 45 | (perform (vector-set! (fetch the-marks) 46 | (fetch thing))) 47 | mcar 48 | (push thing) 49 | (push continue) 50 | (assign continue mcdr) 51 | (assign thing (vector-ref (fetch the-cars) 52 | (fetch thing))) 53 | (goto mark) 54 | mcdr 55 | (pop continue) 56 | (pop thing) 57 | (assign thing 58 | (vector-ref (fetch the-cdrs) 59 | (fetch thing))) 60 | (goto mark) 61 | done 62 | (goto (fetch continue))) 63 | 64 | (define-assembly auxiliary-gc 65 | (assign free '()) 66 | (assign scan (1- (fetch memtop))) 67 | slp 68 | (branch (negative? (fetch scan)) 69 | end) 70 | (assign mark-flag 71 | (vector-ref (fetch the-marks) 72 | (fetch scan))) 73 | (branch (= (fetch mark-flag) 74 | 1) 75 | unmk) 76 | (perform (vector-set! (fetch the-cdrs) 77 | (fetch scan) 78 | (fetch free))) 79 | (assign free (fetch scan)) 80 | (assign scan (1- (fetch scan))) 81 | (goto slp) 82 | unmk 83 | (perform (vector-set! (fetch the-marks) 84 | (fetch scan) 85 | 0)) 86 | (assign scan (1- (fetch scan))) 87 | (goto slp) 88 | end) 89 | 90 | ;; cited fastest garbage collector algorithm: 91 | ;; Minsky-Feinchel-Yochelson Garbage Collector Algorithm, 61' 92 | 93 | ;; The lecture finishes introducing the halting problem 94 | ;; and problems not computables. 95 | 96 | (defun inf () 97 | (lambda () (funcall (lambda (x) (funcall x x)) 98 | (lambda (x) (funcall x x))))) 99 | 100 | (defun diag1 (p) 101 | (if (safe? p p) 102 | (inf) 103 | 3)) 104 | 105 | (diag1 diag1) ;; safe? 106 | 107 | ;; diag here comes to the Diagonal Argument of Cantor 108 | ;; proving real numbers are not countable by showing 109 | ;; that the numbers between a segment line is bigger than 110 | ;; all set of natural numbers -- Sussman explanation 111 | (defun diag2 (p) 112 | (if (safe? p p) 113 | (other-than (p p)) 114 | 'false)) 115 | 116 | 117 | (defun other-than (p) 118 | (if (eq p 'x) 119 | 'x 120 | p)) 121 | 122 | ;; IS NOT POSSIBLE TO TELL IF A FUNCTION WILL GET A INFINITE LOOP 123 | ;; UNTIL YOU RUN IT. 124 | -------------------------------------------------------------------------------- /mit-6.001/1A-heuristic-square-root.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | #| A heuristic method to calculate the 5 | square root of a number x based on the 6 | Hero of Alexandria's alogrithm. 7 | |# 8 | 9 | 10 | (defparameter *error-limit* 0.001) 11 | 12 | (defparameter *tests* '((square-root 2) 13 | (square-root 12) 14 | (square-root 25) 15 | (square-root 144) 16 | (square-root 165465) 17 | )) 18 | 19 | (defun square (x) 20 | (* x x)) 21 | 22 | (defun average (x y) 23 | (/ (+ x y) 2)) 24 | 25 | ;; square-root black box 26 | ;; functional by function composition 27 | (defun square-root (x &key (error-limit *error-limit*)) 28 | (labels ((improve (guess) 29 | (average guess (/ x guess))) 30 | (good-enough? (guess) 31 | (< (abs (- (square guess) x)) 32 | error-limit)) 33 | (try (guess) 34 | (if (good-enough? guess) 35 | guess 36 | (try (improve guess))))) 37 | 38 | (float (try 1)))) 39 | 40 | 41 | ;; eval-test black-box 42 | ;; functional 43 | (defun eval-test (test fn limit) 44 | (labels ((call-test (test) 45 | (let ((output (eval test))) 46 | (format t "~s -> ~f ~%" test output) 47 | output))) 48 | (let ((x (cadr test))) 49 | (if (< (abs (- (call-test test) (funcall fn x))) 50 | limit) 51 | :nice 52 | :fail)))) 53 | 54 | ;; non-functional use variable global *error-limit* and *tests* 55 | (defun run-tests () 56 | (format t "Running tests with limit ~f ~%" *error-limit*) 57 | (let* ((results (loop for x in *tests* collect (eval-test x #'sqrt *error-limit*))) 58 | (total (length results)) 59 | (pass (count :nice results))) 60 | (format t "Tests avalied [pass/total]: ~d/~d ~%" pass total))) 61 | 62 | 63 | (run-tests) 64 | -------------------------------------------------------------------------------- /mit-6.001/1B-iterative-vs-recursive.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defun print-eval (expression) 5 | (eval (print expression))) 6 | 7 | ;; linear iterative solution 8 | ;; time=O(x); space=O(1) 9 | (defun sum-i (x y) 10 | (if (= x 0) 11 | y 12 | (print-eval `(sum-i (1- ,x) (1+ ,y))))) 13 | 14 | 15 | ;; linear recursive solution 16 | ;; time=O(x); space=O(x) 17 | ;; but lisp have tail call optimization 18 | ;; so we receive the same of sum-i on printing 19 | (defun sum-r (x y) 20 | (if (= x 0) 21 | y 22 | (print-eval `(1+ (sum-r (1- ,x) ,y))))) 23 | 24 | 25 | (defun fib-r (n) 26 | (if (< n 2) 27 | n 28 | (print-eval `(+ (fib-r (- ,n 1)) 29 | (fib-r (- ,n 2)))))) 30 | 31 | (print (sum-i 10 20)) 32 | (print (sum-r 10 20)) 33 | (print (fib-r 10)) -------------------------------------------------------------------------------- /mit-6.001/2A-lambda-expressions.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; function Σ 5 | ;; func must be a lambda(x) expression 6 | (defun Σ (λ a b &optional (next #'1+)) 7 | (if (> a b) 8 | 0 9 | (+ (funcall λ a) 10 | (Σ λ (funcall next a) b)))) 11 | 12 | ;; I would like to avoid the use of 'funcall' for calling 13 | ;; lambda expressions passed to Σ, is ugly. 14 | 15 | (defun sum-square (a b) 16 | (Σ #'(lambda(x) (* x x)) a b)) 17 | 18 | (defun sum-int (a b) 19 | (Σ #'(lambda(x) x) a b)) 20 | 21 | (defun sum-pi (a b) 22 | (Σ #'(lambda (x) (/ 1 (* x (+ 1 2)))) 23 | a b 24 | #'(lambda (x) (+ x 4)))) 25 | 26 | (sum-square 1 10) 27 | (sum-int 1 10) 28 | (Σ #'(lambda(x) (/ 1 x)) 1 10 #'(lambda (x) (+ 4 x))) 29 | (Σ #'(lambda(x) (- x)) 1 10) -------------------------------------------------------------------------------- /mit-6.001/2B-compund-data.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | ;; Here we used cons to construct pair of things 6 | ;; that structures are also called 'list structures' 7 | ;; after all, list are essentially recursively cons 8 | ;; (list 1 2 3) → (cons 1 (cons 2 (cons 3 nil))) 9 | 10 | 11 | #| Map of abstraction for: Rational Numbers 12 | 13 | Usage → Rational numbers → Pairs of nubmers 14 | ↓ ↓ ↓ 15 | +rat make-rat cons 16 | *rat numer car 17 | /rat denom cdr 18 | -rat inverse-rat gcd 19 | |# 20 | 21 | 22 | ;; i don't use gcd as name of that procedure 23 | ;; because clisp have a reserved name-space locked as macro for gcd 24 | ;; what are funny... because, why sucks gcd is a macro?! 25 | (defun my-gcd(a b) 26 | (if (= b 0) 27 | a 28 | (my-gcd b (mod a b)))) 29 | 30 | ;; rational numbers (re-implementations) 31 | (defun make-rat (n d) 32 | (let ((g (my-gcd n d))) 33 | (cons (/ n g) 34 | (/ d g)))) 35 | 36 | (defun numer (r) 37 | (car r)) 38 | 39 | (defun denom (r) 40 | (cdr r)) 41 | 42 | (defun inverse-rat (x) 43 | (make-rat (denom x) (numer x))) 44 | 45 | (defun +rat (x y) 46 | (make-rat (+ (* (numer x) (denom y)) 47 | (* (numer y) (denom y))) 48 | (* (denom x) (denom y)))) 49 | 50 | (defun -rat (x y) 51 | (+rat x (make-rat (- (numer y)) (denom y)))) 52 | 53 | (defun *rat (x y) 54 | (make-rat (* (numer x) (numer y)) 55 | (* (denom x) (denom y)))) 56 | 57 | (defun /rat (x y) 58 | (*rat x (inverse-rat y))) 59 | 60 | 61 | #| Map of abstraction fir: Segments and Vectors 62 | 63 | Segments → Vectors → Pairs of nubmers 64 | ↓ ↓ ↓ 65 | make-seg make-vector cons 66 | seg-start xcor car 67 | seg-end ycor cdr 68 | 69 | |# 70 | 71 | 72 | ;; vectors bi-dimensional 73 | ;; whose x y are numbers 74 | (defun make-vector (x y) (cons x y)) 75 | 76 | (defun xcor (v) (car v)) 77 | 78 | (defun ycor (v) (cdr v)) 79 | 80 | ;; whose p q are vectors 81 | (defun make-seg (p q) (cons p q)) 82 | 83 | (defun seg-start (s) (car s)) 84 | 85 | (defun seg-end (s) (cdr s)) 86 | 87 | (defun average (x y) 88 | (/ (+ x y) 2)) 89 | 90 | (defun midpoint (s) 91 | (let ((a (seg-start s)) 92 | (b (seg-end s))) 93 | (make-vector 94 | (average (xcor a) (xcor b)) 95 | (average (ycor b) (ycor b))))) 96 | 97 | (defun segment-length (s) 98 | (flet ((square (x) (* x x))) 99 | (let ((dx (- (xcor (seg-end s)) 100 | (xcor (seg-start s)))) 101 | (dy (- (ycor (seg-end s)) 102 | (ycor (seg-start s))))) 103 | (sqrt (+ (square dx) 104 | (square dy)))))) 105 | 106 | 107 | 108 | ;; but all are defined by cons, car cdr... primitive procedures?? 109 | ;; So... I say: "Hey, is primitive! Is magic". NO!! 110 | ;; We can build that procedures that way: 111 | 112 | 113 | (defun crazy-cons (a b) 114 | (lambda (pick) 115 | (cond ((= pick 1) a) 116 | ((= pick 2) b)))) 117 | 118 | (defun crazy-car (λ) (funcall λ 1)) 119 | 120 | (defun crazy-cdr (λ) (funcall λ 2)) -------------------------------------------------------------------------------- /mit-6.001/3A-data-abstraction.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; 2D Vector Abstraction 5 | 6 | (setf (symbol-function 'make-vector) #'cons) 7 | (setf (symbol-function 'xcor) #'car) 8 | (setf (symbol-function 'ycor) #'cdr) 9 | 10 | (defun +vect (u v) 11 | (make-vector (+ (xcor u) 12 | (xcor v)) 13 | (+ (ycor u) 14 | (ycor v)))) 15 | 16 | (defun scale (s v) 17 | (make-vector (* s (xcor v)) 18 | (* s (ycor v)))) 19 | 20 | 21 | ;; Segment on Plane Abstraction 22 | 23 | (setf (symbol-function 'make-seg) #'cons) 24 | (setf (symbol-function 'seg-start) #'car) 25 | (setf (symbol-function 'seg-end) #'cdr) 26 | 27 | (defun segment-length (segment) 28 | (let* ((x (- (xcor (seg-start segment)) 29 | (xcor (seg-end segment)))) 30 | (y (- (ycor (seg-start segment)) 31 | (ycor (seg-end segment))))) 32 | (sqrt (+ (* x x) 33 | (* y y))))) 34 | 35 | ;; Data can be grouped using cons and a 36 | ;; general construction is a List 37 | 38 | ;; List construction 39 | (cons 1 (cons 2 (cons 3 nil))) ;; => (1 2 3) 40 | (list 1 2 3) ;; => 1 2 3 41 | 42 | ;; And accessed using car and cdr 43 | 44 | (defparameter 1-to-4 (list 1 2 3 4)) 45 | (car 1-to-4) ;; 1 46 | (cdr 1-to-4) ;; (2 3 4) 47 | (car (cdr 1-to-4)) ;; (2) 48 | 49 | ;; Recursive data is useful for recursive procedures 50 | ;; We will implement a naive implementation of function map and for-each 51 | 52 | (defun naive-map (p l) 53 | "Apply the p procedure at each element of list l 54 | and return a list" 55 | (if (null l) 56 | nil 57 | (cons (funcall p (car l)) 58 | (naive-map p (cdr l))))) 59 | 60 | (naive-map #'1+ 1-to-4) 61 | (mapcar (lambda (x) (+ x 1)) 1-to-4 ) ;; default implementation 62 | 63 | (defun for-each (p l) 64 | "Apply the p procedure at each element of list and 65 | return *done*" 66 | (if (null l) 67 | '*done* 68 | (progn (funcall p (car l)) 69 | (for-each p (cdr l))))) 70 | 71 | (for-each #'print 1-to-4) 72 | 73 | ;; Second Part: Peter's Language (DSL) about images 74 | 75 | ;; primitive: picture 76 | 77 | ;; rectangle 78 | ;; (make-rect) 79 | ;; (horiz) 80 | ;; (vert) 81 | ;; (origin) 82 | 83 | (defun make-rect (origin horiz vert) 84 | (cons origin (cons horiz vert))) 85 | 86 | (setf (symbol-function 'origin) #'car) 87 | (setf (symbol-function 'horiz) #'cadr) 88 | (setf (symbol-function 'vert) #'cddr) 89 | 90 | (defun coord-map (rect) 91 | (lambda (point) 92 | (+vect (+vect (scale (xcor point) 93 | (horiz rect)) 94 | (scale (ycor point) 95 | (vert rect))) 96 | (origin rect)))) 97 | 98 | (defun make-picture (seglist) 99 | (lambda (rect) 100 | (for-each 101 | (lambda (s) 102 | (drawline 103 | ((coord-map rect) (seg-start s)) 104 | ((coord-map rect) (seg-end s)))) 105 | seglist))) 106 | 107 | (defun beside (p1 p2 a) 108 | (lambda (rect) 109 | (funcall p1 (make-rect 110 | (origin rect) 111 | (scale a (horiz rect)) 112 | (vert rect))) 113 | (funcall p2 (make-rect 114 | (+vect (origin rect) 115 | (scale a (horiz rect))) 116 | (scale (- 1 a) (horiz rect)) 117 | (vert rect))))) 118 | 119 | 120 | (defun rotate90 (pict) 121 | (lambda (rect) 122 | (funcall pict (make-rect (+vect (origin rect) 123 | (horiz rect)) 124 | (vert rect) 125 | (scale -1 (horiz rect)))))) 126 | 127 | (defun right-push (p n a) 128 | (if (= n 0) 129 | p 130 | (beside p (right-push p (1- n) a) a))) 131 | 132 | 133 | ;; this is a example how can be powerful writing a domain-specific-language 134 | ;; instead breaking your big task and a tree of tasks. 135 | -------------------------------------------------------------------------------- /mit-6.001/3B-symbolic-differentiation.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | (defparameter *dx* 0.0001) 6 | 7 | (defun deriv-numerical (f) 8 | (lambda (x) 9 | (/ (- (funcall f (+ x *dx*)) 10 | (funcall f x)) 11 | *dx*))) 12 | 13 | ;; x^3 => 3x^2 14 | ;; 2^3 => 8 15 | ;; 3 * (2^2) => 12 16 | (funcall (deriv-numerical (lambda (x) (* x x x))) 2) ;; => 11.987 17 | 18 | (defun constant? (exp var) 19 | (and (atom exp) 20 | (not (eq exp var)))) 21 | 22 | (defun same-var? (exp var) 23 | (and (atom exp) 24 | (eq exp var))) 25 | 26 | (defun sum? (exp) 27 | (and (not (atom exp)) 28 | (eq (car exp) '+))) 29 | 30 | (defun power? (exp) 31 | (and (not (atom exp)) 32 | (eq (car exp) '^))) 33 | 34 | (defun make-sum (a1 a2) 35 | (list '+ a1 a2)) 36 | 37 | (defun make-product (m1 m2) 38 | (list '* m1 m2)) 39 | 40 | (defun power-rule (exp) 41 | (let ((base (cadr exp)) 42 | (pow (caddr exp))) 43 | (list '* pow `(^ ,base ,(1- pow))))) 44 | (deriv '(^ x 3) 'x) 45 | 46 | (setf (symbol-function 'a1) #'cadr) 47 | (setf (symbol-function 'a2) #'caddr) 48 | (setf (symbol-function 'm1) #'cadr) 49 | (setf (symbol-function 'm2) #'caddr) 50 | (setf (symbol-function '^) #'expt) ;; power symbol function 51 | 52 | (defun product? (exp) 53 | (and (not (atom exp)) 54 | (eq (car exp) '*))) 55 | 56 | (defun deriv (exp var) 57 | (cond ((constant? exp var) 0) 58 | ((same-var? exp var) 1) 59 | ((sum? exp) 60 | (make-sum (deriv (a1 exp) var) 61 | (deriv (a2 exp) var))) 62 | ((product? exp) 63 | (make-sum 64 | (make-product (m1 exp) 65 | (deriv (m2 exp) var)) 66 | (make-product (m2 exp) 67 | (deriv (m1 exp) var)))) 68 | ((power? exp) (power-rule exp)))) 69 | 70 | (defparameter foo '(+ (* a ( * x x)) 71 | (+ (* b x) c))) 72 | ;; second version of representation 73 | ;; simplifying algebraic expressions 74 | 75 | (defun make-sum (a1 a2) 76 | (cond ((and (numberp a1) 77 | (numberp a2)) 78 | (+ a1 a2)) 79 | ((and (numberp a1) (= a1 0)) 80 | a2) 81 | ((and (numberp a2) (= a2 0)) 82 | a1) 83 | (t (list '+ a1 a2)))) 84 | 85 | (defun make-product (m1 m2) 86 | (cond ((and (numberp m1) 87 | (numberp m2)) 88 | (+ m1 m2)) 89 | ((or (and (numberp m1) (= m1 0)) 90 | (and (numberp m2) (= m2 0))) 91 | 0) 92 | ((and (numberp m1) (= m1 1)) 93 | m2) 94 | ((and (numberp m2) (= m2 1)) 95 | m1) 96 | (t (list '* m1 m2)))) 97 | 98 | (deriv foo 'x) 99 | -------------------------------------------------------------------------------- /mit-6.001/4A-pattern-matching.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; WARNING: THIS CODE WAS COPIED DIRECTLY FROM SICP AND I DON'T TESTED IT 5 | 6 | ;; In the original SICP lectures instead the symbol '=>' is used the colon ':' 7 | ;; however that char is reserved at least on SBCL and a error is dispatched when 8 | ;; this is evaluated 9 | (defparameter deriv-rules '(;; constant 10 | ((dd (?c c) (? x)) 0) 11 | ;; same var 12 | ((dd (?v x) (? x)) 1) 13 | ;; another var 14 | ((dd (?v y) (? x)) 0) 15 | ;; sum rule 16 | ((dd (+ (? x1) (? x2)) (? x)) 17 | (+ (dd (=> x1) (=> x)) 18 | (dd (=> x2) (=> x)))) 19 | ;; multiplication rule 20 | ((dd (* (? x1) (? x2)) (? x)) 21 | (+ (* (=> x1) (dd (=> x2) (=> x))) 22 | (* (=> x2) (dd (=> x1) (=> x))))) 23 | ;; exponentiation rule 24 | ((dd (** (? fx) (? n)) (? x)) 25 | (* (* (=> n) 26 | (** (=> fx) (1- (=> n)))) 27 | (dd (=> fx) (=> x)))))) 28 | 29 | (defparameter algebra-rules '(;; if the operands are constants, evaluate it 30 | ;; (+ 1 2) => 3 31 | (((? op) (?c e1) (?c e2)) 32 | (=> (op e1 e2))) 33 | 34 | ;; if second operand is constant and first not, swap 35 | ;; (+ x 1) => (+ 1 x) 36 | (((? op) (? e1) (?c e2)) 37 | ((=> op) (=> e2) (=> e1) )) 38 | 39 | ;; if something sums 0, return that thing 40 | ;; (+ 0 x) => x 41 | ((+ 0 (? e)) (=> e)) 42 | 43 | ;; if something multiplies 1, just return that 44 | ;; (* 1 x) => x 45 | ((* 1 (? e)) (=> e)) 46 | 47 | ;; anything multiplied by zero is zero 48 | ;; (* 0 x) => 0 49 | ((* 0 (? e)) 0) 50 | 51 | ;; constant multiplication 52 | ;; (* 2 (* 2 x)) => (* 4 x) 53 | ((* (?c e1) (* (?c e2) (? e3))) 54 | (* (=> (* e1 e2)) (=> e3))) 55 | 56 | ;; aesthetic multiplication simplification 57 | ;; (* x (* 5 y)) => (* 5 (* x y)) 58 | ((* (? e1 (* (?c e2) (? e3)))) 59 | (* (=> e2) (* (=> e1) (=> e3)))) 60 | 61 | ;; sum evaluation if is possible 62 | ;; (+ 5 (+ 3 x)) => (+ 8 x) 63 | ((+ (?c e1) (+ (?c e2) (? e3))) 64 | (+ (=> (+ e1 e2)) (=> e3))) 65 | 66 | ;; aesthetic sum simplification 67 | ;; (+ x (+ 2 y)) => (+ 2 (+ x y)) 68 | (((+ (? e1) (+ (?c e2) (? e3))) 69 | (+ (=> e2) (+ (=> e1) (=> e3))))) 70 | 71 | ;; commutative multiplication property 72 | ;; (* (* x y) z) => (* x (* y z)) 73 | ((* (* (? e1) (? e2)) (? e3)) 74 | (* (=> e1) (* (=> e2) (=> e3)))) 75 | 76 | ;; commutative sum property 77 | ;; (+ (+ x y) z) => (+ x (+ y z)) 78 | ((+ (+ (? e1) (? e2)) (? e3)) 79 | (+ (=> e1) (+ (=> e2) (=> e3)))) 80 | 81 | ;; algebraic sum 82 | ;; (+ (* 2 x) (* 4 x)) => (* 6 x) 83 | ((+ (* (?c a) (? x)) (* (?c b) (? x))) 84 | (* (=> (+ a b)) (=> x))) 85 | 86 | ;; distribution rule of product over sum 87 | ((* (? c) (+ (? d) (? e))) 88 | (+ (* (=> c) (=> d)) 89 | (* (=> c) (=> e)))))) 90 | 91 | ;; matcher machine 92 | ;; pattern 93 | ;; ↓ 94 | ;; +---------+ 95 | ;; | | 96 | ;; expression → | MATCHER | → dict 97 | ;; | | 98 | ;; +---------+ 99 | ;; ↑ 100 | ;; dict 101 | ;; 102 | 103 | (defparameter empty-dictionary '()) 104 | 105 | (defun extend-dictionary (pat dat dict) 106 | (let* ((name (variable-name pat)) 107 | (v (assq name dict))) 108 | (cond ((null v) 109 | (cons (list name dat) dict)) 110 | ((eq (cadr v) dat) dict) 111 | (t 'failed)))) 112 | 113 | (defun lookup (var dict) 114 | (let ((v (assq var dict))) 115 | (if (null v) 116 | var 117 | (cadr v)))) 118 | 119 | (defun match (pat exp dict) 120 | (cond ((eq dict 'failed) 'failed) 121 | ((atom pat) 122 | (if (atom exp) 123 | (if (eq pat exp) 124 | dict 125 | 'failed) 126 | 'failed)) 127 | ((arbitrary-constants? pat) 128 | (if (constant? exp) 129 | (extend-dict pat exp dict) 130 | 'failed)) 131 | ((arbitrary-variable? pat) 132 | (if (variable? exp) 133 | (extend-dict pat exp dict) 134 | 'failed)) 135 | ((arbirary-expression? pat) 136 | (extend-dict pat exp dict)) 137 | ((atom exp) 'failed) 138 | (t (match (cdr pat) 139 | (cdr exp) 140 | (match (car pat) 141 | (car exp) 142 | dict))))) 143 | 144 | (defun instantiate (skeleton dict) 145 | (defun loop-inst (s) 146 | (cond ((atom s) s) 147 | ((skeleton-evaluation? s) 148 | (evaluate (eval-exp s) dict)) 149 | (t (cons (loop-inst (car s)) 150 | (loop-inst (cdr s)))))) 151 | (loop-inst skeleton)) 152 | 153 | (defun evaluate (form dict) 154 | (if (atom form) 155 | (lookup form dict) 156 | (apply 157 | (eval (lookup (car form) dict) 158 | user-initial-environment) 159 | (mapcar (lambda (v) 160 | (lookup v dict)) 161 | (cdr form))))) 162 | 163 | 164 | (defun simplifier (the-rules) 165 | (defun try-rules (exp) 166 | (defun scan (rules) 167 | (if (null rules) 168 | exp 169 | (let ((dict (match (pattern (car rules)) 170 | exp 171 | (empty-dictionary)))) 172 | (if (eq dict 'failed) 173 | (scan (cdr rules)) 174 | (simplify-exp 175 | (instantiate 176 | (skeleton (car rules)) 177 | dict)))))) 178 | (scan the-rules)) 179 | (defun simplify-parts (exp) 180 | (if (null exp) 181 | '() 182 | (cons (simplify-exp (car exp)) 183 | (simplify-parts (cdr exp))))) 184 | (defun simplify-exp (exp) 185 | (try-rules (if (compound? exp) 186 | (simplify-parts exp) 187 | exp))) 188 | 189 | simplify-exp) 190 | 191 | 192 | (setf (symbol-function 'dsimp) (simplifier deriv-rules)) 193 | -------------------------------------------------------------------------------- /mit-6.001/4B-generic-operators.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; Arithmetic operations on 5 | ;; complex numbers 6 | 7 | 8 | ;; ** COMPLEX NUMBERS PROPERTIES ** 9 | ;; Re(Z1 + Z2) = Re(Z1) + Re(Z2) 10 | ;; Im(Z1 + Z2) = Im(Z1) + Im(Z2) 11 | ;; Mag(Z1 * Z2) = Mag(Z1) * Mag(Z2) 12 | ;; Angle(Z1 * Z2) = Angle(Z1) + Angle(Z2) 13 | 14 | ;; ** SELECTORS ** 15 | ;; REAL-PART -> Z 16 | ;; IMG-PART -> Z 17 | ;; MAGNITUDE -> Z 18 | ;; ANGLE -> Z 19 | 20 | ;; ** CONSTRUCTORS ** 21 | ;; MAKE-RECTANGULAR -> X -> Y 22 | ;; MAKE-POLAR -> R -> A 23 | 24 | ;; SOLUTION FOR MULTIPLE REPRESENTATIONS 25 | ;; TYPED DATA + GENERIC OPERATORS 26 | 27 | ;; constructor 28 | (defun attach-type (type contents) 29 | (cons type contents)) 30 | 31 | ;; selectors 32 | (defun complex-type (datum) 33 | (car datum)) 34 | 35 | (defun contents (datum) 36 | (cdr datum)) 37 | 38 | ;; type predicates 39 | 40 | (defun rectangular? (z) 41 | (eq (complex-type z) 'rectangular)) 42 | 43 | (defun polar? (z) 44 | (eq (complex-type z) 'polar)) 45 | 46 | ;; GEORGE IMPLEMENTATION 47 | ;; Representing complex numbers as 48 | ;; pairs REAL-PART, IMAGINARY-PART 49 | 50 | (defun make-rectangular (x y) 51 | (attach-type 'rectangular (cons x y))) 52 | 53 | (defun real-part-rectangular (z) 54 | (car z)) 55 | 56 | (defun imag-part-rectangular (z) 57 | (cdr z)) 58 | 59 | (defun magnitude-rectangular (z) 60 | (sqrt (+ (square (car z)) 61 | (square (cdr z))))) 62 | 63 | (defun angle-rectangular (z) 64 | (atan (/ (cdr z) (car z)))) 65 | 66 | ;; MARTHA IMPLEMENTATION 67 | ;; Representing complex numbers as 68 | ;; pairs MAGNITUDE, ANGLE 69 | 70 | 71 | (defun make-polar (r a) 72 | (attach-type 'polar (cons r a))) 73 | 74 | (defun magnitude-polar (z) 75 | (car z)) 76 | 77 | (defun angle-polar (z) 78 | (cdr z)) 79 | 80 | (defun real-part-polar (z) 81 | (* (car z) (cos (cdr z)))) 82 | 83 | (defun imag-part-polar (z) 84 | (* (car z) (sin (cdr z)))) 85 | 86 | ;; GENERIC SELECTORS FOR COMPLEX NUMBERS 87 | 88 | 89 | (defun real-part (z) 90 | (cond ((rectangular? z) 91 | (real-part-rectangular 92 | (contents z))) 93 | ((polar? z) 94 | (real-part-polar 95 | (contents z))))) 96 | 97 | (defun imag-part (z) 98 | (cond ((rectangular? z) 99 | (imag-part-rectangular 100 | (contents z))) 101 | ((polar? z) 102 | (imag-part-polar))) 103 | (contents z)) 104 | 105 | (defun magnitude (z) 106 | (cond ((rectangular? z) 107 | (magnitude-rectangular 108 | (contents z))) 109 | ((polar? z) 110 | (magnitude-polar 111 | (contents z))))) 112 | 113 | (defun angle (z) 114 | (cond ((rectangular? z) 115 | (angle-rectangular 116 | (contents z))) 117 | ((polar? z) 118 | (angle-polar 119 | (contents z))))) 120 | 121 | (defun +c (z1 z2) 122 | (make-rectangular 123 | (+ (real-part z1) (real-part z2)) 124 | (+ (imag-part z1) (imag-part z2)))) 125 | 126 | (defun -c (z1 z2) 127 | (make-rectangular 128 | (- (real-part z1) (real-part z2)) 129 | (- (imag-part z1) (imag-part z2)))) 130 | 131 | (defun *c (z1 z2) 132 | (make-polar 133 | (* (magnitude z1) (magnitude z2)) 134 | (+ (angle z1) (angle z2)))) 135 | 136 | (defun /c (z1 z2) 137 | (make-polar 138 | (/ (magnitude z1) (magnitude z2)) 139 | (- (angle z1) (angle z2)))) 140 | 141 | ;; an alternative way to represent this, avoid the MANAGER is using a table 142 | ;; for relate each type and the correct procedure. In the lecture is build on top using this technique for rational, polynomial, complex and ordinary numbers the generic operators add, sub, mul and div. 143 | -------------------------------------------------------------------------------- /mit-6.001/5A-state-and-side-effects.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; mathematical truths using functional programming 5 | ;; don't change state, the same funcall for same params 6 | ;; the result is the same 7 | 8 | (defun fact (n) 9 | (if (<= n 1) 10 | 1 11 | (* n (fact (1- n))))) 12 | 13 | ;; imperative way 14 | (defun fact (n) 15 | (let ((i 1) 16 | (m 1)) 17 | (labels ((iter () 18 | (if (> i n) 19 | m 20 | (progn (setq m (* i m)) 21 | (setq i (1+ i)) 22 | (iter))))) 23 | (iter)))) 24 | 25 | (fact 10) 26 | 27 | ;; using mutation of state 28 | ;; lambda used as closure 29 | (defun make-counter (n) 30 | (lambda () 31 | (setq n (1+ n)) 32 | n)) 33 | 34 | (setf (symbol-function 'c1) (make-counter 1)) 35 | (setf (symbol-function 'c2) (make-counter 10)) 36 | (c1) ;; independents states for n 37 | (c2) ;; makes change on our environment 38 | 39 | ;; examples with free variable 40 | 41 | (defun free-variable-x () 42 | (lambda (x) (lambda (y) (* x y)))) 43 | ;; ↑ x is a free-variable get in the environment at that moment 44 | -------------------------------------------------------------------------------- /mit-6.001/5B-computational-objects.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; digital circuit builder 5 | ;; computational objects using state and assignment (previous lecture) 6 | ;; 7 | ;; 8 | ;; |\ 9 | ;; ----| *--- (inverter) 10 | ;; |/ 11 | ;; ____ 12 | ;; ---| \ 13 | ;; | |-- (and-gate) 14 | ;; ---|____/ 15 | ;; _______ 16 | ;; \ \ 17 | ;; | |-- (or-gate) 18 | ;; ___/___/ 19 | ;; 20 | 21 | ;; agenda primitives 22 | ;; (make-agenda) 23 | ;; (current-time agenda) 24 | ;; (empty-agenda? agenda) 25 | ;; (add-to-agenda! time action agenda) 26 | ;; (first-item agenda) 27 | ;; (remove-first-item agenda) 28 | 29 | ;; implementing the agenda is George problem. 30 | 31 | (defparameter the-agenda (make-agenda)) 32 | (defparameter inverter-delay 2) 33 | (defparameter and-gate-delay 3) 34 | (defparameter or-gate-delay 5) 35 | 36 | (defun after-delay (delay action) 37 | (add-to-agenda! 38 | (+ delay (current-time the-agenda)) 39 | action 40 | the-agenda)) 41 | 42 | (defun propagate () 43 | (cond ((empty-agenda? the-agenda) 'done) 44 | (t (progn (funcall (first-item the-agenda)) 45 | (remove-first-item! the-agenda) 46 | (propagate))))) 47 | 48 | (defun call-each (procedures) 49 | (cond ((null procedures) 'done) 50 | (t (progn (funcall (car procedures)) 51 | (call-each (cdr procedures)))))) 52 | 53 | (defun get-signal (wire) 54 | (wire 'get-signal)) 55 | 56 | (defun set-signal! (wire new-value) 57 | (apply (wire 'set-signal!) '(new-value))) 58 | 59 | (defun add-action! (wire action-proc) 60 | (apply (wire 'add-action!) '(action-proc))) 61 | 62 | (defun make-wire () 63 | (let ((signal 0) 64 | (action-procs '())) 65 | (labels ((set-my-signal! (new) 66 | (cond ((= signal new) 'done) 67 | (t (progn (setq signal new) 68 | (call-each action-procs))))) 69 | (accept-action-proc (proc) 70 | (setq action-procs (cons proc action-procs)) 71 | (proc)) 72 | (dispatch (m) 73 | (cond ((eq m 'get-signal) signal) 74 | ((eq m 'set-signal) set-my-signal!) 75 | ((eq m 'add-action) 76 | accept=action-proc) 77 | (t (error "Bad message" m))))) 78 | dispatch))) 79 | 80 | (defun error (&rest messages) 81 | (loop for m in messages do (princ m))) 82 | 83 | (defun logical-not (s) 84 | (cond ((= s 0) 1) 85 | ((= s 1) 0) 86 | (t (error *invalid-signal* s)))) 87 | 88 | (defun logical-and (s1 s2) 89 | (cond ((and (eq s1 1) 90 | (eq s2 1)) 1) 91 | (t 0))) 92 | 93 | (defun logical-or (s1 s2) 94 | (cond ((or (eq s1 1) 95 | (eq s2 1)) 1) 96 | (t 0))) 97 | 98 | 99 | (defun inverter (in out) 100 | (labels ((inverter-in () 101 | (let ((new (logical-not (get-signal in)))) 102 | (after-dealy inverter-delay (lambda () (set-signal out new)))))) 103 | (add-action! in invert-in))) 104 | 105 | (defun and-gate (a1 a2 output) 106 | (labels ((and-action-procedure () 107 | (let ((new-value (logical-and (get-signal a1) 108 | (get-signal a2)))) 109 | (after-delay and-gate-delay 110 | (lambda () 111 | (set-signal! output 112 | new-value)))))) 113 | (add-action! a1 and-action-procedure) 114 | (add-action! a2 and-action-procedure))) 115 | 116 | (defun or-gate (a1 a2 output) 117 | (labels ((or-action-procedure () 118 | (let ((new-value (logical-or (get-signal a1) 119 | (get-signal a2)))) 120 | (after-delay or-gate-delay 121 | (lambda () 122 | (set-signal! output 123 | new-value)))))) 124 | (add-action! a1 or-action-procedure) 125 | (add-action! a2 or-action-procedure))) 126 | 127 | (defparameter a (make-wire)) 128 | (defparameter b (make-wire)) 129 | (defparameter c (make-wire)) 130 | (defparameter d (make-wire)) 131 | (defparameter e (make-wire)) 132 | (defparameter s (make-wire)) 133 | 134 | (or-gate a b d) 135 | (and-gate a b c) 136 | (inverter c e) 137 | (and-gate d e s) 138 | 139 | (defun half-adder (a b s c) 140 | (let ((d (make-wire)) 141 | (e (make-wire))) 142 | (or-gate a b d) 143 | (and-gate a b c) 144 | (inverter c e) 145 | (and-gate d e s))) 146 | 147 | (defun full-adder (a b c-in sum c-out) 148 | (let ((s (make-wire)) 149 | (c1 (make-wire)) 150 | (c2 (make-wire))) 151 | (half-adder b c-in s c1) 152 | (half-adder a s sum c2) 153 | (or-gate c1 c2 c-out))) 154 | 155 | 156 | ;; Bonus => Lambda Calculus Mutable Data 157 | ;; Redefining Cons with only lambdas 158 | 159 | (defun cons-lambda (x y) 160 | (lambda (m) 161 | (apply m '(x 162 | y 163 | (lambda (n) (setq x y)) 164 | (lambda (n) (setq y n)))))) 165 | 166 | (defun car-lambda (c) 167 | (apply c (list (lambda (a d sa sd) a)))) 168 | 169 | (defun cdr-lambda (c) 170 | (apply c (list (lambda (a d sa sd) d)))) 171 | 172 | (defun set-car! (c n) 173 | (apply c (list (lambda (a d sa sd) (sa n))))) 174 | 175 | (defun set-cdr! (c n) 176 | (apply c (list (lambda (a d sa sd) (sd n))))) 177 | -------------------------------------------------------------------------------- /mit-6.001/6A-streams-I.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | 5 | ;; THIS LECTURE IS ABOUT STREAMS AND GENERATORS 6 | 7 | 8 | ;; previous concepts defined: 9 | ;; * STATE 10 | ;; * ASSIGNMENT 11 | ;; * CHANGE (VARIABLE) 12 | ;; * TIME 13 | ;; * IDENTITY (ABOUT CAR/CDRS) 14 | ;; * OBJECT 15 | ;; * SHARING (STATE) 16 | 17 | 18 | ;; without using streams and high abstract procedures, solve that two problems: 19 | ;; sum-odd-squares on tree and sum the odd fib numbers from a interval [n, m] 20 | 21 | 22 | (defun leaf-node? (tree) 23 | (atom tree)) 24 | 25 | (defun square (n) 26 | (* n n)) 27 | 28 | (defun left-branch (tree) 29 | (car tree)) 30 | 31 | (defun right-branch (tree) 32 | (cdr tree)) 33 | 34 | (defun sum-odd-squares (tree) 35 | (if (leaf-node? tree) 36 | (if (and (numberp tree) (oddp tree)) 37 | (square tree) 38 | 0) 39 | (+ (sum-odd-squares 40 | (left-branch tree)) 41 | (sum-odd-squares 42 | (right-branch tree))))) 43 | 44 | ;; tail cail optimized, from O(2^n) => O(n) 45 | (defun fib (n) 46 | (labels ((tail-call-fib (n acc1 acc2) 47 | (if (= n 0) 48 | acc1 49 | (tail-call-fib (1- n) acc2 (+ acc1 acc2))))) 50 | (tail-call-fib n 0 1))) 51 | 52 | (defun odd-fibs (n) 53 | (labels ((next (k) 54 | (if (> k n) 55 | nil 56 | (let ((f (fib k))) 57 | (if (oddp f) 58 | (cons f (next (1+ k))) 59 | (next (1+ k))))))) 60 | (next 1))) 61 | 62 | ;; However, we can imagine that problems in a signal processing evaluation, like that 63 | 64 | ;; sum-odd-squares 65 | ;; enumerates-leaves => filter-odd => map-square => (acc '+ '0) 66 | 67 | ;; odd-fibs 68 | ;; enum-interval => map-fib => filter-odd => (acc 'cons '()) 69 | 70 | ;; This is like streams, so we will define data abstraction for streams 71 | ;; primitives 72 | ;; (cons-stream x y) 73 | ;; (head s) 74 | ;; (tail s) 75 | ;; (the-empty-stream) 76 | 77 | ;; for any x and y 78 | ;; (head (cons-stream x y)) => x 79 | ;; (tail (cons-stream x y)) => y 80 | 81 | ;; this seems very likely cons, car and cdr, right? 82 | ;; but not! streams are lazy evaluated 83 | 84 | 85 | (defun delay (x) 86 | (lambda () x)) 87 | 88 | (defun force (x) 89 | (let* ((exp (funcall x)) 90 | (func (car exp)) 91 | (args (cdr exp))) 92 | (apply func args))) 93 | 94 | ;; i tried define this as macro to avoid the quotation for y, 95 | ;; but just doesn't works T_T 96 | ;; old version :: 97 | ;; (defmacro cons-stream (x delayed) 98 | ;; `(cons ,x (delay (list ,@delayed)))) 99 | ;; the code fails on enumerate-tree about 100 | ;; (cons tree the-empty-stream) ;; => (cons tree (list nil)) 101 | (defun cons-stream (x y) 102 | (cons x (delay y))) 103 | 104 | (defun head (x) 105 | (car x)) 106 | 107 | (defun tail (x) 108 | (force (cdr x))) 109 | 110 | (defparameter the-empty-stream '()) 111 | 112 | (defun empty-stream? (x) 113 | (null x)) 114 | 115 | (defun map-stream (proc s) 116 | (if (empty-stream? s) 117 | the-empty-stream 118 | (cons-stream 119 | (funcall proc (head s)) 120 | `(map-stream ,proc ,(tail s))))) 121 | 122 | (defun filter (pred s) 123 | (cond ((empty-stream? s) the-empty-stream) 124 | ((funcall pred (head s)) 125 | (cons-stream (head s) 126 | `(filter ,pred 127 | ,(tail s)))) 128 | (t (filter pred (tail s))))) 129 | 130 | (defun accumulate (combiner init-val s) 131 | (if (empty-stream? s) 132 | init-val 133 | (funcall combiner (head s) 134 | (accumulate combiner 135 | init-val 136 | (tail s))))) 137 | 138 | (defun append-streams (s1 s2) 139 | (if (empty-stream? s1) 140 | s2 141 | (cons-stream (head s1) 142 | `(append-streams ,(tail s1) 143 | ,s2)))) 144 | 145 | (defun enumerate-tree (tree) 146 | (if (leaf-node? tree) 147 | (cons-stream tree 148 | the-empty-stream) 149 | (append-streams 150 | (enumerate-tree 151 | (left-branch tree)) 152 | (enumerate-tree 153 | (right-branch tree))))) 154 | 155 | (defun enum-interval (low high) 156 | (if (> low high) 157 | the-empty-stream 158 | (cons-stream low `(enum-interval ,(1+ low) ,high)))) 159 | 160 | 161 | (defun sum-odd-squares-stream (tree) 162 | (accumulate #'+ 0 163 | (mapcar #'square 164 | (filter #'oddp 165 | (enumerate-tree tree))))) 166 | 167 | 168 | (defun odd-fibs-stream (n) 169 | (accumulate #'cons '() 170 | (filter #'oddp 171 | (mapcar #'fib (enum-interval 1 n))))) 172 | 173 | 174 | (defun flatten (st-of-st) 175 | (accumulate #'append-streams 176 | the-empty-stream 177 | st-of-st)) 178 | 179 | (defun flat-map (f s) 180 | (flatten (map-stream f s))) 181 | 182 | 183 | (defun prime? (n) 184 | (let ((divisors (loop for x from 2 to (round (sqrt n)) collect x))) 185 | (loop for div in divisors never (eq (mod n div) 0)))) 186 | 187 | (defun prime-sum-pairs (n) 188 | (map-stream #'(lambda (p) 189 | (list (car p) 190 | (cadr p) 191 | (+ (car p) (cadr p)))) 192 | (filter 193 | (lambda (p) 194 | (prime? (+ (car p) (cadr p)))) 195 | (flat-map #'(lambda (i) 196 | (map-stream (lambda (j) (list i j)) 197 | (enum-interval 1 (1- i)))) 198 | (enum-interval 1 n))))) 199 | 200 | (defun range (a b) 201 | (enum-interval a b)) 202 | 203 | (defun eval-stream (s) 204 | (if (empty-stream? s) 205 | nil 206 | (cons (head s) (eval-stream (tail s))))) 207 | 208 | (eval-stream (range 1 10)) 209 | 210 | (prime? 13) 211 | (head (tail (filter #'prime? (enum-interval 10000 100000000000000)))) 212 | -------------------------------------------------------------------------------- /mit-6.001/6B-streams-II.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (load "6A-streams-I.lisp") 5 | 6 | 7 | ;; i just watched this lecture, some behaviors of stream don't works well here 8 | ;; i can't define things like (define ones (cons-stream 1 ones)) 9 | ;; the primitive for streams on previous lecture is messed up 10 | ;; the problem is store a operand of procedure without evaluated it before 11 | ;; as common lisp eval all your operands before doing a funcall, 12 | ;; delay procedure doesn't works well. 13 | -------------------------------------------------------------------------------- /mit-6.001/7A-metacircular-evaluator-I.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | #| 5 | 6 | -- * A META-CIRCULAR COMPILER OF MINIMAL LISP * -- 7 | 8 | Every function symbol with prefixed '+ is used to not conflict with the namespace of reserved special forms 9 | of the current Lisp compiler. 10 | |# 11 | 12 | ;; assumes lambda exp => (closure ((vars) body) env) 13 | 14 | (defun primitive? (_) 15 | (or _ t)) 16 | 17 | (defun apply-primeop (proc args) 18 | (+apply proc args)) 19 | 20 | 21 | (defun pair-up (vars vals) 22 | (loop for x in vars 23 | for y in vals 24 | collect (cons x y))) 25 | 26 | (defun assq (sym alist) 27 | (cond ((eq alist '()) nil) 28 | ((eq sym (caar alist)) 29 | (car alist)) 30 | (t (assq sym (cdr alist))))) 31 | 32 | (defun lookup (sym env) 33 | (cond ((eq env '()) (error 'UBV)) ;; UNBOUND VARIABLE 34 | (t (funcall (lambda (vcell) 35 | (cond ((eq vcell '()) 36 | (lookup sym (cdr env))) 37 | (t (cdr vcell)))) 38 | (assq sym (car env)))))) 39 | 40 | (defun bind (vars vals env) 41 | (cons (pair-up vars vals) env)) 42 | 43 | (defun +eval (exp env) 44 | (cond ((numberp exp) exp) 45 | ((symbolp exp) (lookup exp env)) 46 | ((eq (car exp) 'quote) (cadr exp)) 47 | ((eq (car exp) 'lambda) 48 | (list 'closure (cdr exp) env)) 49 | ((eq (car exp) 'cond) 50 | (evcond (cdr exp) env)) 51 | (t (+apply (+eval (car exp) env) 52 | (+eval (cdr exp) env))))) 53 | 54 | 55 | (defun +apply (proc args) 56 | (cond ((primitive? proc) 57 | (apply-primeop proc args)) 58 | ((eq (car proc) 'closure) 59 | (+eval (cadadr proc) 60 | (bind (caadr proc) 61 | args 62 | (caddr proc)))) 63 | (t 'error))) 64 | 65 | (defun false? (x) 66 | (eq x nil)) 67 | 68 | (defun evlist (l env) 69 | (cond ((eq l '()) '()) 70 | (t (cons 71 | (+eval (car l) env) 72 | (evlist (cdr l) env))))) 73 | 74 | (defun evcond (clauses env) 75 | (cond ((eq clauses '()) '()) 76 | ((eq (caar clauses) t) 77 | (+eval (cadar clauses) env)) 78 | ((false? (+eval (caar clauses) env)) 79 | (evcond (cdr clauses) env)) 80 | (t (+eval (cadar clauses) env)))) 81 | 82 | 83 | #| Evaluating expression with this compiler using substitution model 84 | 85 | => (eval '(((lambda (x) (lambda (y) (+ x y))) 3) 4) ) 86 | => (apply (eval '((lambda (x) (lambda (y) (+x y))) 3) ) 87 | (evlist '(4) )) 88 | => (apply (eval '((lambda (x) (lambda (y) (+ x y))) 3) ) 89 | (cons (eval '4 ))) 91 | => (apply (eval '((lambda (x) (lambda (y) (+ x y))) 3) ) 92 | (cons 4 '())) 93 | => (apply (eval '((lambda (x) (lambda (y) (+ x y))) 3) ) 94 | '(4)) 95 | => (apply (apply (eval '(lambda (x) (lambda (+ x y))) ) 96 | '(3)) 97 | '(4)) 98 | 99 | => (apply (apply '(closure ((x) (lambda (y) (+ x y))) ) 100 | '(3)) 101 | '(4)) 102 | => (apply (eval '(lambda (y) (+ x y)) ) 103 | '(4)) 104 | => (apply '(closure ((y) (+ x y)) ) 105 | '(4)) 106 | => (eval (+ x y) ) 107 | => (apply (eval '+ ) 108 | (evlist '(x y) )) 109 | => (apply '+ '(3 4)) 110 | 7 111 | 112 | The eval/apply dancing. 113 | 114 | EVAL → PROC, ARGS → APPLY 115 | ↓ ↓ 116 | ====> EXP, ENV <====== 117 | 118 | 119 | |# 120 | 121 | 122 | ;; fixed points :: (Y F) = (Y (Y F)) 123 | 124 | 125 | (defun Y (f) 126 | (funcall (lambda (x) (funcall f x x)) 127 | (lambda (x) (funcall f x x)))) 128 | 129 | ;; (y #'print) bug!, y combinators! 130 | 131 | #| 132 | Y = (lambda (f) 133 | ((lambda (x) (f (x x))) 134 | (lambda (x) (f (x x))))) 135 | 136 | (Y F) = ((lambda (x) (F (x x))) 137 | (lambda (x) (F (x x)))) 138 | = (F ((lambda (x) (F (x x))) 139 | (lambda (x) (F (x x))))) 140 | (Y F) = (F (Y F)) 141 | 142 | |# 143 | -------------------------------------------------------------------------------- /mit-6.001/7B-metacircular-evaluator-II.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (load "7A-metacircular-evaluator-I.lisp") 5 | 6 | #| 7 | == META-CIRCULAR EVALUATOR PART ii == 8 | 9 | A weird interpreter of Lisp written in Lisp to run it in Lisp. Why so much Lisp? I even know what I writing. 10 | Well, let me press the play button for the lecture 7B. 11 | 12 | |# 13 | 14 | 15 | (defun take-many-arguments (x &rest y) 16 | (mapcar #'(lambda (u) (* u x)) 17 | y)) 18 | 19 | (take-many-arguments 5 1 2 3 4 5) 20 | 21 | 22 | ;; some strange modification was done here to support 23 | ;; function lambdas with variadic params 24 | (defun pair-up (vars vals) 25 | (cond ((eq vars '()) 26 | (cond ((eq vals '()) '()) 27 | (t (error 'TMA)))) 28 | ((symbolp vars) 29 | (cons (cons vars vals) '())) 30 | ((eq vals '()) 31 | (error 'TFA)) 32 | (t (cons (cons (car vars) 33 | (car vals)) 34 | (pair-up (cdr vars) 35 | (cdr vals)))))) 36 | 37 | (defun sum (term a next b) 38 | (if (> a b) 39 | 0 40 | (+ (funcall term a) 41 | (sum term 42 | (funcall next a) 43 | next 44 | b)))) 45 | 46 | (defun product (term a next b) 47 | (if (> a b) 48 | 0 49 | (* (funcall term a) 50 | (product term 51 | (funcall next a) 52 | next 53 | b)))) 54 | 55 | (defun sum-powers (a b n) 56 | (sum (lambda (x) (expt x n)) 57 | a 58 | #'1+ 59 | b)) 60 | 61 | (defun product-powers (a b n) 62 | (product (lambda (x) (expt x n)) 63 | a 64 | #'1+ 65 | b)) 66 | 67 | ;; this is not so nice, we have code replication. Hour to do some abstraction here 68 | 69 | ;; => POC 70 | 71 | (defun nth-power (x) 72 | (expt x n)) ;; a problem here, n is isolated into this environment, n => free variable 73 | ;; but how can nth-power know if n is a bound variable when is called? 74 | 75 | ;; the name of that problem is dynamic binding. 76 | 77 | (defun sum-powers (a b n) 78 | (sum #'nth-power a #'1+ b)) 79 | ;; nth-power, with dynamical binding, we try look for the value of n into the environment of caller. 80 | ;; which in that case is sum-of-powers, so will n from nth-power bind to n to sum-powers function body. 81 | 82 | ;; similarly to product we have 83 | 84 | (defun product-powers (a b n) 85 | (product #'nth-power a #'1+ b)) 86 | 87 | ;; for that works we need change the way of +eval from the last lecture is implemented, here is the new +eval: 88 | 89 | ;; we'll kill the lexical scope and statical binding for that, so closures are dead. 90 | 91 | (defun +eval (exp env) 92 | (cond ((numberp exp) exp) 93 | ((symbolp exp) (lookup exp env)) 94 | ((eq (car exp) 'quote) (cadr exp)) 95 | ((eq (car exp) 'lambda) exp) ;; changes here, just return the lambda exp instead closure/env 96 | ((eq (car exp) 'cond) 97 | (evcond (cdr exp) env)) 98 | (t (+apply (+eval (car exp) env) 99 | (evlist (cdr exp) env) ;; also changes here 100 | env)))) 101 | 102 | ;; apply needs be changed too, and gets more complicated 103 | 104 | (defun +apply (proc args env) ;; now apply needs env as parameter! 105 | (cond ((primitive? proc) ;; magic, ignore 106 | (apply-primeop proc args)) 107 | ((eq (car proc) 'lambda) ;; if is lambda 108 | (+eval (caddr proc) ;; body 109 | (bind (cadr proc) ;; vars 110 | args 111 | env)) ;; env provide from the caller of function 112 | (t 'error-unknow-procedure)))) 113 | 114 | 115 | ;; dynamic binding has serious problems because breaks the problem of modularity 116 | ;; the scope is global for all!!!!!!!!!!! because closures will conflict of its internal variables 117 | ;; with the caller and so on 118 | 119 | ;; SO GO TO HELL WITH OF THIS TYPE OF ABSTRACTION HERE! 120 | ;; SCHEME AND COMMON LISP DON'T IMPLEMENTS DYNAMIC BINDING 121 | ;; (however seems JS do as well old lisp implementations) 122 | 123 | 124 | ;; by other hand, we can use a double closure to take n variable passing to them 125 | 126 | ;; pgen => procedure generator 127 | (defun pgen (n) 128 | (lambda (x) (expt x n))) 129 | 130 | (defun sum-powers (a b n) 131 | (sum #'(pgen n) 132 | a 133 | #'1+ 134 | b)) 135 | 136 | (defun product-powers (a b n) 137 | (product #'(pgen n) 138 | a 139 | #'1+ 140 | b)) 141 | 142 | ;; Oh, nice! Sussman talk about the lazy evaluation problem from streams 143 | ;; procedures commented in the earlier lectures. Yes, we have a problem passing in the 144 | ;; way is showed. The arguments, by default, is evaluated first before function call 145 | ;; in Lisp. 146 | 147 | (defun +unless (p c a) 148 | (cond ((not p) c) 149 | (t a))) 150 | 151 | ;; so 152 | 153 | (+unless (= 1 0) 2 (/ 1 0)) ;; is ok, huh? 154 | 155 | ;; NOooot! nOOOT! As Pingu would say. That not will return 2, because before that (/ 1 0) is 156 | ;; evaluated and that procedure call is giant a sin. A ARITHMETIC ERROR IS TROWED INTO YOUR FACE! 157 | 158 | 159 | ;; but if `c` and `a` was delayed automatically? 160 | 161 | 162 | ;; MODE : SCHEME 163 | #| 164 | 165 | (define (unless p (name a) (name c)) 166 | (cond ((not p) a) 167 | (t c))) 168 | 169 | |# 170 | 171 | ;; if this is implemented, we need change again our interpreter/compiler core 172 | 173 | ;; primitives for that type of thing 174 | (defun delay (x) 175 | (lambda () x)) 176 | 177 | (defun force (x) 178 | (funcall x)) 179 | 180 | (defun undelay (x) 181 | (cond ((and (pair? v) 182 | (eq (car v) 'thunk)) 183 | (undelay (eval (cadr v) 184 | (cddr v)))) 185 | (t v))) 186 | 187 | (defun make-delay (exp env) 188 | (cons 'thunk) (cons exp env)) 189 | 190 | (defun +eval (exp env) 191 | (cond ((numberp exp) exp) 192 | ((symbolp exp) (lookup exp env)) 193 | ((eq (car exp) 'quote) (cadr exp)) 194 | ((eq (car exp) 'lambda) 195 | (list 'closure (cdr exp) env)) 196 | ((eq (car exp) 'cond) 197 | (evcond (cdr exp) env)) 198 | (t (+apply (undelay (+eval (car exp) env)) ;; force undelay here 199 | (cdr exp) ;; btw, wtf is undelay? 200 | env)))) ;; we need that again 201 | 202 | (defun evlist (l env) 203 | (cond ((eq 1 '()) nil) 204 | (t (cons (undelay (eval (car l env))) 205 | (evlist (cdr l) env))))) 206 | 207 | (defun gevlist (vars exp env) 208 | (cond ((eq exps nil) nil) 209 | ((symbolp (car vars)) 210 | (cons (eval (car exps) env) 211 | (gevlist (cdr vars) 212 | (cdr exps) 213 | env))) 214 | ((eq? (caar vars) 'name) 215 | (cons (make-delay (car exps) env) 216 | (gevlist (cdr vars) 217 | (cdr exps) 218 | env))) 219 | (t (error 'error-unknown-declaration)))) 220 | 221 | (defun +apply (proc args env) ;; now apply needs env as parameter! 222 | (cond ((primitive? proc) ;; magic, ignore 223 | (apply-primeop proc (evlist args env))) 224 | ((eq (car proc) 'closure) ;; if is lambda 225 | ;; proc = (closure ((bvrs) body) env) 226 | (+eval (cadadr proc) ;; body 227 | (bind (vnames (caadr proc)) ;; vars 228 | (gevlist (caadr proc) 229 | args 230 | env) 231 | (caddr proc))) ;; env provide from the caller of function 232 | (t 'error-unknow-procedure)))) 233 | 234 | ;; evcond needs change too 235 | (defun evcond (clauses env) 236 | (cond ((eq clauses '()) '()) 237 | ((eq (caar clauses) t) 238 | (+eval (cadar clauses) env)) 239 | ((false? (undelay ;; because need predicate evaluates 240 | (+eval (caar clauses) 241 | env))) 242 | (evcond (cdr clauses) env)) 243 | (t (+eval (cadar clauses) env)))) 244 | 245 | 246 | 247 | ;; THIS FUCKING METACIRCULAR EVALUATOR IS REALLY OBSCURE!!! hahaha 248 | -------------------------------------------------------------------------------- /mit-6.001/8A-logic-programming-I.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | #| 5 | Some explorations on Logic Programming and Declarative Programming 6 | 7 | This lecture don't cover the implementation of the query system based on logic! 8 | |# 9 | 10 | ;; (+merge '(4 5 6) '(1 2 3)) => '(1 2 3 4 5 6) 11 | (defun +merge (x y) 12 | (cond ((null x) y) 13 | ((null y) x) 14 | (t (let ((a (car x)) 15 | (b (car y))) 16 | (if (< a b) 17 | (cons a 18 | (+merge (cdr x) y)) 19 | (cons b 20 | (+merge x (cdr y)))))))) 21 | 22 | ;; in logic 23 | 24 | #| 25 | (1 3 7) and (2 4 1) merge-to-form ? 26 | (1 3 7) and ? merge-to-form (1 2 3 4 7 8) 27 | x? and y? merge-to-form (1 2 3 4 7 8) 28 | 29 | Declarative properties, logical thinking. 30 | 31 | The usage of Logic Programming (e.g.:: Prolog) is three: 32 | 33 | 1. To express what is true 34 | 2. Check whether something is true 35 | 3. Find what's is true 36 | 37 | |# 38 | 39 | ;; this macros don't exists on lectures, i put here just for fun and to the file compiles. 40 | 41 | (defvar jobs nil) 42 | (defvar salaries nil) 43 | (defvar supervisors nil) 44 | (defvar addresses nil) 45 | 46 | (defmacro job (who job) 47 | `(push (cons (quote ,who) (quote ,job)) jobs)) 48 | 49 | (defmacro salary (who salary) 50 | `(push (cons (quote ,who) (quote ,salary)) salaries)) 51 | 52 | (defmacro supervisor (who s) 53 | `(push (cons (quote ,who) (quote ,s)) supervisors)) 54 | 55 | (defmacro address (who a) 56 | `(push (cons (quote ,who) (quote ,a)) addresses)) 57 | 58 | 59 | ;; entry 1 60 | (job (Bitdiddle Ben) (computer wizard)) 61 | 62 | (salary (Bitdiddle Ben) 40000) 63 | 64 | (supervisor (Bitdiddle Ben) 65 | (Warbucks Oliver)) 66 | 67 | (address (Bitdiddle Ben) 68 | (Slunerville (Ridge Road) 10)) 69 | 70 | ;; entry 2 71 | (job (Hacker Alyssa P) 72 | (computer programmer)) 73 | 74 | (salary (Hacker Alyssa P) 35000) 75 | 76 | (supervisor (Hacker Alyssa P) 77 | (Bitdiddle Ben)) 78 | 79 | (address (Hacker Alyssa P) 80 | (Cambridge (Mass Ave) 78)) 81 | 82 | ;; entry 3 83 | (job (Tweakit Lan E) 84 | (computer technician)) 85 | 86 | 87 | (salary (Tweakit Len E) 15000) 88 | 89 | (supervisor (Tweakit Len E) 90 | (Bitdiddle Ben)) 91 | 92 | (address (Tweakit Len E) 93 | (Boston (Bay State Road) 22)) 94 | 95 | ;; entry 4 96 | 97 | (job (Reasoner Louis) 98 | (computer programmer trainee)) 99 | 100 | (salary (Reasoner Louis) 20000) 101 | 102 | (supervisor (Reasoner Louis) 103 | (Hacker Alyssa P)) 104 | 105 | (address (Reasoner Louis) 106 | (Slunerville (Pine Tree Road) 107 | 80)) 108 | 109 | 110 | ;; primitives => 111 | ;; * query 112 | ;; ~ like the data entry above 113 | 114 | ;; means of combination => 115 | ;; * and 116 | ;; * not 117 | ;; * or 118 | ;; * lisp-value 119 | 120 | ;; (and (job ?x (computer . ?y)) 121 | ;; (not (and (supervisor ?x ?z) 122 | ;; (job ?z (computer . ?w)))) 123 | 124 | ;; means of abstraction => 125 | ;; * rules 126 | 127 | ;; (rule (bigshot ?x ?dept) ;; conclusion 128 | ;; (and (job ?x (?dept . ?y)) ;; body 129 | ;; (not (and (supervisor ?x ?z) 130 | ;; (job ?z (?dept . ?w)))))) 131 | 132 | ;; backing to the merge problem 133 | 134 | ;; (rule (merge-to-form () ?y ?y)) 135 | ;; (rule (merge-to-form ?y () ?y)) 136 | 137 | #| 138 | 139 | (rule 140 | (merge-to-form (?a . ?x) (?b . ?y) (?b . ?z)) 141 | (and (merge-to-form (?a . ?x) ?y ?z) 142 | (lisp-value > ?a ?b))) 143 | 144 | |# 145 | -------------------------------------------------------------------------------- /mit-6.001/8B-logic-programming-II.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; sample patterns 5 | 6 | #| 7 | 8 | (a ?x c) 9 | 10 | (job ?x (computer ?y)) 11 | 12 | (job ?x (computer . ?y)) 13 | 14 | (a ?x ?x) 15 | 16 | (?x ?y ?y ?x) 17 | 18 | (a . ?x) 19 | 20 | |# 21 | 22 | ;; rule-based system for logic programming using 23 | ;; patter matching 24 | 25 | (load "4A-pattern-matching.lisp") 26 | (match pat data dictionary) ;; needs implements match 27 | ;; in earlier lectures, the primitives for pattern matching 28 | ;; is implemented 29 | 30 | ;; query black box 31 | 32 | ;; ↓ pattern 33 | ;; +-------+ 34 | ;; | | 35 | ;; => initial-dict | QUERY | => dictionary 36 | ;; | | 37 | ;; +-------+ 38 | ;; ↑ database stream 39 | 40 | 41 | ;; means of combinations: NOT, AND, OR 42 | 43 | ;; means of abstraction: rules 44 | 45 | (rule (boss ?z ?d) 46 | (and (job ?x (?d . ?y)) 47 | (supervisor (?x ?z)))) 48 | 49 | 50 | ;; == TO APPLY A RULE 51 | 52 | ;; Evaluate the rule body relative to an environment 53 | ;; formed by unifying the rule conclusion with the 54 | ;; given query. 55 | 56 | 57 | ;; == TO APPLY A PROCEDURE 58 | 59 | ;; Evaluate the procedure body relative to an enviroment 60 | ;; formed by binding the procedure paramaters to the 61 | ;; to the arguments. 62 | 63 | 64 | ;; All humans are mortals 65 | ;; All greeks are humans. 66 | ;; Socrates is greek, 67 | ;;------ syllogism logic ---- 68 | ;; :: Socrates is mortal. 69 | 70 | 71 | (Greek Socrates) 72 | (Greek Plato) 73 | (Greek Zeus) 74 | (god Zeus) 75 | 76 | (rule (mortal ?x) (human ?x)) 77 | (rule (fallible ?x) (human ?x)) 78 | 79 | (rule (human ?x) 80 | (and (Greek ?x) (not (god ?x)))) 81 | 82 | (rule (address ?x Olympus) 83 | (and (greek ?x) (god ?x))) 84 | 85 | (rule (perfect ?x) 86 | (and (not (mortal ?x)) 87 | (not (fallible ?x)))) 88 | 89 | (and (address ?x ?y) 90 | (perfect ?x)) ;; => Mount Olympus (Zeus) 91 | 92 | (and (perfect ?x) 93 | (address ?x ?y)) ;; Nothing 94 | 95 | 96 | ;; But who is right? We can makes assumption of our 97 | ;; data here about that: Zeus is not mortal, Zeus 98 | ;; is not mortal, just because he is not human? 99 | ;; This is not sufficient information. 100 | 101 | ;; NOT here is NOT from the logic! 102 | ;; The NOT here is a filter of a closed world, 103 | ;; the complements of a assumption. 104 | ;; Logic makes assumptions of only two states. 105 | ;; This is a big problem. 106 | -------------------------------------------------------------------------------- /mit-6.001/9A-register-machines.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; The Hardware Machine Description in Lisp 5 | 6 | ;; a simple macro to that file compiles. 7 | (defmacro define-machine (machine &rest body) 8 | `(defparameter ,machine (quote ,body))) 9 | 10 | (defun gcd. (a b) 11 | (if (= b 0) 12 | A 13 | (gcd. b (mod a b)))) 14 | 15 | ;; A machine description for the GCD procedure/machine 16 | (define-machine gcd-machine 17 | (registers a b t) 18 | (controller 19 | main (assign a (read)) 20 | (assign b (read)) 21 | loop (branch (zerop (fetch b)) 22 | done) 23 | (assign t (mod (fetch a) (fetch b))) 24 | (assign a (fetch b)) 25 | (assign b (fetch t)) 26 | (goto loop) 27 | done (perform (print (fetch a))) 28 | (goto main))) 29 | 30 | 31 | (defun fact (n) 32 | (if (= n 1) 33 | 1 34 | (* n (fact (1- n))))) 35 | 36 | 37 | (fact 10000) 38 | 39 | ;; fact is a problem, because before build this machine, we need fact exists 40 | ;; and remember the last operations to reduce the overall expression 41 | ;; only in the end => n! = n*(n -1)...1 42 | ;; for that, will put each `n` on stack before the recursive call 43 | 44 | 45 | (define-machine fact-machine 46 | (registers n) 47 | (assign continue done) 48 | (controller 49 | loop (branch (= 1 (fetch n)) base) 50 | (save continue) 51 | (save n) 52 | (assign n (-1 (fetch n))) 53 | (assign continue aft) 54 | (goto loop) 55 | aft (restore n) 56 | (restore continue) 57 | (assign val (* (fetch n) (fetch val))) 58 | (goto (fetch continue)) 59 | base (assign val (fetch n)) 60 | (goto (fetch continue)) 61 | done)) 62 | 63 | 64 | 65 | (defun fib (n) 66 | (if (< n 2) 67 | n 68 | (+ (fib (- n 1)) 69 | (fib (- n 2))))) 70 | 71 | ;; this is not lisp code, ok? 72 | ;; is a embed language for machine code made in lisp 73 | ;; to be interpreted in lisp, but is not lisp!!!!!!!! 74 | (define-machine fib-machine 75 | (registers n) 76 | (controller 77 | (assign continue fib-done) 78 | fib-loop ; n contains arg, continue as recipient 79 | (branch (< (fetch n) 2) immediate-ans) 80 | (save continue) 81 | (assign continue after-fibs-n-1) 82 | (save n) 83 | (assign n (- (fetch n) 1)) 84 | (goto fib-loop) 85 | after-fib-n-1 ; after get the first fib 86 | (restore n) 87 | (restore continue) ; useless? 88 | (assign n (- (fetch n) 2)) 89 | (save continue) ; useless? 90 | (assign continue after-fib-n-2) 91 | (save val) 92 | (goto fib-loop) 93 | after-fib-n-2 94 | (assign n (fetch val)) ;; fib(n - 2) 95 | (restore val) 96 | (restore continue) 97 | (assign val 98 | (+ (fetch val) 99 | (fetch n))) ;; fib(n -1) + fib(n - 2) 100 | (goto fetch continue) 101 | immediate-ans 102 | (assign val (fetch n)) 103 | (goto (fetch continue)) 104 | fib-done)) 105 | 106 | 107 | ;; Machine primitives: DATAPATH + CONTROLLER + MEMORY 108 | 109 | 110 | ;; actually, this really seems a low-level description for 111 | ;; a machine, Lisp Assembly? HAHA... But I don't get the whole 112 | ;; picture of this lecture. Maybe I need rewatch this in someday 113 | -------------------------------------------------------------------------------- /mit-6.001/9B-explicit-control-evaluator.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | ;; A review about language design using Lisp, what we've done until now: 5 | ;; Picture language by Peter Henderson 6 | ;; Digital Logic Language 7 | ;; Query Language (Logic Programming like Prolog) 8 | 9 | ;; CONCRETE COMPUTATION HERE! 10 | 11 | 12 | ;; ======> LISP 13 | 14 | ;; Meta-circular evaluator was based on Lisp for Lisp. Eval/Apply solving fixed-point equations 15 | 16 | 17 | ;; This stuff seems magic, but right now we'll destroy all the magic using the register machine 18 | 19 | ;; again, primitives: DATA-PATHS, FINITE-STATE CONTROLLER AND STACK 20 | 21 | 22 | 23 | ;; lisp-user -> chars => reader => lisp memory structure => eval => 24 | ;; primitive-operations => printer => lisp-user 25 | 26 | #| 27 | :: REGISTER USAGE IN EVALUATOR MACHINE :: 28 | 29 | EXP expression to be evaluated 30 | ENV evaluation environment 31 | 32 | FUN procedure to be applied 33 | ARGL list of evaluated arguments 34 | 35 | CONTINUE place to go to next 36 | 37 | VAL result of evaluation 38 | 39 | UNEV temporary register for expressions 40 | 41 | |# 42 | 43 | #| 44 | SAMPLE EVALUATOR-MACHINE OPERATIONS 45 | (assign val (fetch exp)) 46 | 47 | (branch (conditional? (fetch exp)) 48 | ev-cond) 49 | 50 | (assign exp (first-clause (fetch-exp))) 51 | 52 | (assign val (look-variable-value (fetch exp) 53 | (fetch env))) 54 | |# 55 | 56 | 57 | ;; evaluator for LISP in LISP 58 | ;; using abstract syntax from SICP book (little different of lecture from Gerald) 59 | (defun eval. (exp env) 60 | (cond ((self-evaluating ? exp) exp) 61 | ((quoted? exp) 62 | (text-of-quotation exp)) 63 | ... 64 | ((application? exp) 65 | (apply 66 | (eval (operator exp) env) 67 | (list-of-values (operands exp) 68 | env))) 69 | (t (error 'unknown-expression)))) 70 | 71 | 72 | (defun apply. (proc args) 73 | (cond ((primitive-proc? proc) 74 | (primitive-apply proc args)) 75 | ((compound-proc? proc) 76 | (eval-sequence (proc-body proc) 77 | (extend-environment 78 | (parameters proc) 79 | args 80 | (proc-environment proc)))) 81 | (t (error unknown-proc-type)))) 82 | 83 | 84 | ;; eval/apply cicle :: eval => procedure, arguments => 85 | ;; apply => expression, environment => 86 | ;; eval 87 | 88 | 89 | #| 90 | :: CONTRACT THAT EVAL-DISPATCH FULFILLS :: 91 | 92 | - The EXP register holds an expression to 93 | be evaluated; 94 | 95 | - The ENV register holds the environment in which the expression 96 | is to be evaluated; 97 | 98 | - The CONTINUE register holds a place to go to next; 99 | 100 | - The result will be left in the VAL register. Contents of all 101 | other registers may be destroyed; 102 | 103 | |# 104 | 105 | 106 | #| 107 | 108 | :: CONTRACT THAT APPLY-DISPATCH FULFILLS :: 109 | 110 | - The ARGL register contains a list of arguments; 111 | 112 | - The FUN register contains a procedure to be applied; 113 | 114 | - The top of the STACK holds a place to go to next; 115 | 116 | - The result will be left in the VAL register. The stack will be 117 | popped. Contents of all other registers may be destroyed; 118 | 119 | |# 120 | 121 | (load "9A-register-machines.lisp") 122 | 123 | (define-machine eval-dispatch 124 | (branch (self-evaluating? (fetch exp)) 125 | ev-self-eval) 126 | (branch (variable? (fetch exp)) 127 | ev-variable) 128 | 129 | < more especial forms > 130 | 131 | (branch (application? (fetch exp)) 132 | ev-appliations) 133 | (goto unknow-expression-error)) 134 | 135 | (define-machine ev-self-eval 136 | (assign val (fetch exp)) 137 | (goto (fetch continue))) 138 | 139 | 140 | (define-machine ev-variable 141 | (assign val (lookup-variable-value (fetch exp))) 142 | (goto (fetch continue))) 143 | 144 | 145 | (define-machine ev-application 146 | (assign unev (operands (fetch exp))) 147 | (assign exp (oeprator (fetch exp))) 148 | (save continue) 149 | (save env) 150 | (save unev) 151 | (assign continu eval-args) 152 | (goto eval-dispatch)) 153 | 154 | 155 | (define-machine eval-args 156 | (restore unev) 157 | (restore env) 158 | (assign fun (fetch val)) 159 | (save fun) 160 | (assign argl '()) 161 | (goto eval-arg-loop)) 162 | 163 | (define-machine eval-arg-loop 164 | (save argl) 165 | (assign exp (first-operand (fetch unev))) 166 | (branch (last-operand? (fetch (unev))) 167 | (eval-last-arg)) 168 | (save env) 169 | (save unev) 170 | (assign continue accumulate-arg) 171 | (goto eval-dispatch)) 172 | 173 | (define-machine accumulate-arg 174 | (restore unev) 175 | (restore env) 176 | (restore argl) 177 | (assign argl (cons (fetch val) 178 | (fetch arg1))) 179 | (assign unev (rest-operands (fetch unev))) 180 | (goto eval-arg-loop)) 181 | 182 | (define-machine apply-dispatch 183 | (branch (primitive-proc? (fetch fun) 184 | primitive-apply)) 185 | (branch (compound-proc? (fetch fun) 186 | compound-apply)) 187 | (goto unknown-proc-type-error)) 188 | 189 | 190 | (define-machine primitive-apply 191 | (assign val (apply-primitive-proc (fetch fun) 192 | (fetch argl))) 193 | (restore continue) 194 | (goto (fetch continue))) 195 | 196 | 197 | (define-machine compound-apply 198 | (assign exp (procedure-body (fetch fun))) 199 | (assign env (make-bindings (fetch fun) 200 | (fetch arg1))) 201 | (restore continue) 202 | (goto eval-dispatch)) 203 | 204 | (defun f (a b) 205 | (+ a b)) 206 | ;; 207 | (defvar x 3) 208 | (defvar y 4) 209 | 210 | (f x y) 211 | 212 | (defun fact-rec (n) 213 | (if (<= n 1) 214 | 1 215 | (* n 216 | (fact-rec (1- n))))) 217 | 218 | -------------------------------------------------------------------------------- /random/command-line-args.lisp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sbcl 2 | ;; Common Lisp Script 3 | ;; Manoel Vilela 4 | 5 | (defun my-command-line () 6 | (or 7 | #+SBCL sb-ext:*posix-argv* 8 | #+CLISP *args* 9 | #+LISPWORKS system:*line-arguments-list* 10 | #+CMU extensions:*command-line-words* 11 | nil)) 12 | 13 | (format t "~&~S~&" (my-command-line)) -------------------------------------------------------------------------------- /random/compose.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (defun compose (&rest funs) 5 | (let ((funs (reverse funs))) 6 | (lambda (&rest args) 7 | (loop with result = args 8 | for fun in funs 9 | do (setf result (list (apply fun result))) 10 | finally (return (car result)))))) 11 | 12 | (funcall (compose #'abs #'-) 1 2) #| ==> 1 |# -------------------------------------------------------------------------------- /random/game-of-life-sdl.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela -- but i not have wrote that script 3 | 4 | (ql:quickload 'lispbuilder-sdl) 5 | (ql:quickload 'lispbuilder-sdl-gfx) 6 | (ql:quickload 'alexandria) 7 | 8 | (defparameter *world* (make-array '(100 100) :element-type 'bit)) 9 | 10 | ;; initialize 11 | (defun init-world! (world) 12 | (loop for i from 0 to (1- (array-dimension world 0)) do 13 | (loop for j from 0 to (1- (array-dimension world 1)) do 14 | (setf (aref world i j) (if (zerop (random 7)) 1 0))))) 15 | 16 | (defun count-neighboring-individual (i j world) 17 | (let ((next-i (if (= i (1- (array-dimension world 0))) 0 (1+ i))) 18 | (prev-i (if (= i 0) (1- (array-dimension world 0)) (1- i))) 19 | (next-j (if (= j (1- (array-dimension world 1))) 0 (1+ j))) 20 | (prev-j (if (= j 0) (1- (array-dimension world 1)) (1- j)))) 21 | (+ (aref world prev-i prev-j) 22 | (aref world prev-i j) 23 | (aref world prev-i next-j) 24 | (aref world i prev-j) 25 | (aref world i next-j) 26 | (aref world next-i prev-j) 27 | (aref world next-i j) 28 | (aref world next-i next-j)))) 29 | 30 | ;; return next generation world 31 | (defun update-next-generation (world) 32 | (let ((next-world (alexandria:copy-array world))) 33 | (loop for i from 0 to (1- (array-dimension world 0)) do 34 | (loop for j from 0 to (1- (array-dimension world 1)) do 35 | (cond ((and (zerop (aref world i j)) ; birth 36 | (= (count-neighboring-individual i j world) 3)) 37 | (setf (aref next-world i j) 1)) 38 | ((and (= (aref world i j) 1) ; die by under-population or overcrowding 39 | (or (<= (count-neighboring-individual i j world) 1) 40 | (>= (count-neighboring-individual i j world) 4))) 41 | (setf (aref next-world i j) 0))))) 42 | next-world)) 43 | 44 | (defun life () 45 | (sdl:with-init () 46 | (sdl:window 400 400) ; size of window 47 | (setf (sdl:frame-rate) 60) ; set frame-rate 60fps 48 | (init-world! *world*) 49 | (sdl:with-events () 50 | (:quit-event () t) 51 | (:idle () 52 | (setf *world* (update-next-generation *world*)) 53 | (loop for i from 0 to (1- (array-dimension *world* 0)) do 54 | (loop for j from 0 to (1- (array-dimension *world* 1)) do 55 | (if (= (aref *world* i j) 0) 56 | (sdl-gfx:draw-box (sdl:rectangle :x (* i 4) :y (* j 4) :w 4 :h 4) 57 | :color sdl:*black*) 58 | (sdl-gfx:draw-box (sdl:rectangle :x (* i 4) :y (* j 4) :w 4 :h 4) 59 | :color sdl:*white*)))) 60 | (sdl:update-display))))) 61 | 62 | (life) 63 | -------------------------------------------------------------------------------- /random/namespaces-troll.lisp: -------------------------------------------------------------------------------- 1 | ;; Common Lisp Script 2 | ;; Manoel Vilela 3 | 4 | (flet ((foo (when funcall) 5 | (when (< 3 when) 6 | (funcall funcall)) when)) 7 | (loop :named funcall :for funcall :from 1 :collect 8 | (foo funcall (lambda () (loop-finish))))) --------------------------------------------------------------------------------