#+TITLE: The Little Schemer - tags :: [[file:../20200604222651-lisp.org][lisp]] [[file:../20200604222704-functional_programming.org][functional programming]] [[file:../20200718223520-scheme.org][Scheme]] Some of my examples are written in Emacs Lisp, as at the time I hadn't installed a Scheme interpreter. It doesn't make a huge difference. * 1. Toys - an atom is a simple element, separated by spaces - a list is a series of atoms, surrounded by parentheses - s-expression :: an atom or a list - =car= retrieves first element of list #+BEGIN_SRC emacs-lisp (car '(123)) #+END_SRC #+RESULTS: : 123 - =cdr= retrieves everything besides the first element of a list #+BEGIN_SRC emacs-lisp (cdr '(a b c)) #+END_SRC #+RESULTS: | b | c | - =cons= adds an atom to the front of a list #+BEGIN_SRC emacs-lisp (cons 100 '(a b c)) (cons '(a b) '(c d)) #+END_SRC #+RESULTS: | (a b) | c | d | - =null= tests for empty lists #+BEGIN_SRC emacs-lisp (null ()) #+END_SRC #+RESULTS: : t - =atom= tests for atoms #+BEGIN_SRC emacs-lisp (atom 123) #+END_SRC #+RESULTS: : t - =eq= tests equality for non-numeric atoms #+BEGIN_SRC emacs-lisp (eq 'a 'b) #+END_SRC #+RESULTS: * 2. Do It, Do It Again - always ask =null?= first! - this chapter serves as a good introduction to recursion and tracing through lisp programs * 3. Cons the Magnificent - ~cons~ is for building lists - *important*: when building lists from lists, figure out what the first element looks like, then recur over the ~cdr~ of the rest of the list #+begin_src emacs-lisp :exports both (defun firsts (l) (cond ((null l) '()) (t (cons (car (car l)) (firsts (cdr l)) )))) (firsts '((a b) (c d))) ;; => (a c) #+end_src #+RESULTS: | a | c | * 5. *Oh My Gawd*: It's full of Stars - In Scheme (and other Lisps?) a * suffix means "repeat this throughout the list." More specifically, it means to recur on the ~car~ of the list. For example: #+begin_src scheme :eval never (rember* 'sauce ((tomato sauce) bean sauce)) ;; => ((tomato) bean) (rember 'sauce ((tomato sauce) bean sauce)) ;; => ((tomato) bean sauce) #+end_src - The first commandment says that, when recurring, you must ask between two to three questions. For a list of atoms, it's "~null?~" and "~else~", and for S-expressions, it's "~null?~", "~atom? (car l)~", and "~else~" - The fourth commandment says that, when recurring, you must change at least one argument. When traversing over a list, decrement the list using ~cdr~ - The sixth commandment is very important: "simplify only after the function is correct" * 6. Shadows - The Seventh Commandment :: Recur on the /subparts/ that are of the same nature - An attempt at ~value~ (for only ~+~) in Emacs Lisp: #+begin_src emacs-lisp (defun my-value (nexp) (cond ((atom nexp) nexp) ((eq (car (cdr nexp)) '+) (+ (value (car nexp)) (value (car (cdr (cdr nexp)))))) (t nexp))) (my-value '(1 + 2)) #+end_src #+RESULTS: : 3 - The Eighth Commandment :: Use help functions to abstract from representations