summaryrefslogtreecommitdiffstats
path: root/books/Seasoned Schemer
blob: 0bc63466a91c8b6be6260d5bead7bf4487222797 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
============================
The Seasoned Schemer
============================

:by: Daniel Friedman and Matthias Felleisen 
:Edition: First (1st) 

See also `Scheme </k/software/scheme/>`__. This book is a sequel 
to `The Little Schemer`_; The Reasoned Schemer is a paralel exploration of 
logical programming.

One of the things I liked about learning a programming language this way, or
maybe just about scheme in general, is the seperation between the specification
and implementations. Usually when I start learning a new language I try to 
break it as fast as possible and I am most interested in how certain little
tricky bits are handled (are the file handles cross platform? does it catch
infinite recursion? what kind of errors are thrown when? how big are the 
primitives and simple objects/user defined data types?). These are the
imporant day to day issues and are a good basis for choosing a language to get
work done in, but it's kind of like searching for anti-aliasing in digital
photos or scanning the edges of a wall for painting mistakes. Sometimes the
big picture is the whole point and it's worth putting up with small flaws.

.. _The Little Schemer: /k/books/littleschemer/

Issues/Omissions 
--------------------------
The Y combinator function is never defined in this book, I had to copy it out of 
`The Little Schemer`_; 

    (define Y
      (lambda (thing)
        ((lambda (le)
           ((lambda (f) (f f))
            (lambda (f) (le (lambda (x) ((f f) x))))))
         thing)))

Also ``eqlist?``::

    (define eqlist?
      (lambda (a b)
        (cond
         ((and (null? a) (null? b)) #t)
         ((or (null? a) (null? b)) #f)
         ((and (atom? (car a)) (atom? (car b)))
	       (and (eqlist? (cdr a) (cdr b))))
         ((or (atom? (car a)) (atom? (car b))) #f)
         (else (and (eqlist? (car a) (car b)) (eqlist? (cdr a) (cdr b)))))))

MIT/GNU Scheme doesn't seem to have ``letcc`` or ``try``; I stuck with
``call-with-current-continuation``:

    (call-with-current-continuation (lambda (hook) ...)
    ; is the same as
    (letcc hook (...))

    ; as noted in the book (p. 89)
    (try x a b)
    ; is the same as
    (letcc success 
      (letcc x 
        (success a)) 
      b)
    ; is the same as
    (call-with-current-continuation 
      (lambda (success)
        (begin
          (call-with-current-continuation
            (lambda (x)
              (success a)))
          b)))

When reimplementing scheme at the end of the book, I'm kind of miffed that the
(letcc ...) definition basically just uses letcc, because magic North Pole
compasses seem like the most interesting part.

Notes
-----------------
Y-bang is the "applicative-order imperative Y combinator"::

    (define Y-bang
      (lambda (f)
        (letrec
	    ((h (f (lambda (arg) (h arg)))))
          h)))

At one point I wondered::

    Is there any language/interpreter which, when it runs into an undefined
    value, lets you define it on the spot? Would be great for learners.

MIT/GNU Scheme, of course, has this feature in the error REPL. But I never
noticed it.

The Next 10 Commandments
--------------------------

The Eleventh Commandment
    Use additional arguments when a function needs to know what other 
    arguments to the function have been like so far.

The Twelfth Commandment
    Use (letrec ..) to remove arguments that do not change for 
    recursive applications.

The Thirteenth Commandment
    Use (letrec ...) to hide and protect functions.

The Fifteenth Commandment
    Use (let ...) to name the values of repeated expressions in a function
    definition if they may be evaluated twice for one and same use of the
    function. And use (let ...) to name the values of expressions (without
    set!) that are re-evaluated every time a function is used.

The Sixteenth Commandment
    Use (set! ...) only with names define in (let ...)s

The Seventeenth Commandment
    Use (set! x ...) for (let ((x ..)) ..)) only if there is at least one
    (lambda .. between it and the (let ..), or if the new value for x is a 
    function that refers to x.

The Eighteenth Commandment
    Use (set! x ...) only when the value that x refers to is no longer needed.

The Nineteenth Commandment
    Use (set! ...) to remember valuable things between two distinct uses of a 
    function.

The Twentieth Commandment
    When thinking about a value created with (letcc ...), write down the
    function that is equivalent but does not forget. Then, when you use it,
    remember to forget.

**I love that last sentence!**