-
Notifications
You must be signed in to change notification settings - Fork 0
/
sicp.tex
319 lines (250 loc) · 9.73 KB
/
sicp.tex
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
% Intended LaTeX compiler: lualatex
\documentclass[a4paper, titlepage, twoside]{article}
\usepackage{graphicx}
\usepackage{longtable}
\usepackage{wrapfig}
\usepackage{rotating}
\usepackage[normalem]{ulem}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsfonts}
\usepackage{capt-of}
\usepackage{hyperref}
\pagestyle{headings}
\usepackage{fontspec}
\setmainfont{Linux Libertine}
\setmonofont{Iosevka}
\usepackage{unicode-math}
\setmathfont{Libertinus Math}
\usepackage{microtype}
\usepackage{svg}
\usepackage[margin=1.3in]{geometry}
\renewcommand{\baselinestretch}{1.2}
\usepackage[font={small}, labelfont={bf}]{caption}
\usepackage{minted}
\usemintedstyle{friendly}
\setminted{frame=single, framesep=2mm, linenos=true}
\RequirePackage{fancyvrb}
\DefineVerbatimEnvironment{verbatim}{Verbatim}{frame=single, label=Results, vspace=5mm}
\usepackage{etoolbox}
\AtBeginEnvironment{quote}{\itshape}
%% ox-latex features:
% !announce-start, !guess-pollyglossia, !guess-babel, !guess-inputenc,
% caption, maths, !announce-end.
\usepackage{capt-of}
\usepackage{amsmath}
\usepackage{amssymb}
%% end ox-latex features
\author{Konstantinos Chousos}
\date{\today}
\title{\textbf{Structure and Interpretation of Computer Programs}\\\medskip
\large Exercise solutions}
\hypersetup{
pdfauthor={Konstantinos Chousos},
pdftitle={\textbf{Structure and Interpretation of Computer Programs}},
pdfkeywords={},
pdfsubject={},
pdfcreator={Emacs 29.0.91 (Org mode 9.7-pre)},
pdflang={English},
colorlinks,
linkcolor=blue,
citecolor=red,
urlcolor=blue}\begin{document}
\maketitle
\section*{Introduction}
\label{sec:org1a19912}
This document contains my solutions to the exercises of the \emph{Abelson, Sussman \& Sussman (2002) Structure and Interpretation of Computer Programs, MIT Press} book. It will be updated to reflect my current progress. Each subsection consists of an exercise. The exercise is copied over from the book and presented in italics, followed by my (hopefully correct) solution.
Instead of reading from the PDF, I study SICP through its TeXInfo format\footnote{\url{https://www.neilvandyke.org/sicp-texi/}}. This way, I read the material, interact with the REPL\footnote{see ``Read-Eval-Print-Loop''} and take notes all from my editor of choice, Emacs. For more details about my workflow, you can read my accompanying blog post\footnote{\url{https://kchousos.github.io/posts/sicp-in-emacs/}}.
This document is written in Org-Mode. The code blocks are evaluated using Org-Babel, which is also used to \emph{tangle} the resulting \href{./sicp.rkt}{sicp.rkt} file and \emph{weave} this very PDF, as in literate programming parlance.
Racket is used for implementing the exercises, using the \texttt{sicp} package\footnote{\url{https://docs.racket-lang.org/sicp-manual/index.html}}. Other possible options are guile and GNU/MIT-scheme.
\newpage
\section*{Chapter 1}
\label{sec:org7094ad3}
\subsection*{1.1}
\label{sec:org0965c86}
\begin{quote}
Below is a sequence of expressions. What is the result printed by the interpreter in response to each expression? Assume that the sequence is to be evaluated in the order in which it is presented.
\end{quote}
The interpreter's expected results are in the comments under each expression.
\begin{minted}[]{racket}
10
;; 10
(+ 5 3 4)
;; 12
(- 9 1)
;; 8
(/ 6 2)
;; 3
(+ (* 2 4) (- 4 6))
;; 6
(define a 3)
;;
(define b (+ a 1))
;;
(+ a b (* a b))
;; 19
(= a b)
;; #f
(if (and (> b a) (< b (* a b)))
b
a)
;; 4
(cond ((= a 4) 6)
((= b 4) (+ 6 7 a))
(else 25))
;; 16
(+ 2 (if (> b a) b a))
;; 6
(* (cond ((> a b) a)
((< a b) b)
(else -1))
(+ a 1))
;; 16
\end{minted}
\subsection*{1.2}
\label{sec:orga911e64}
\begin{quote}
Translate the following expression into prefix form.
\begin{equation}
\label{eq:1}
\frac{5+4+(2 - (3 - (6 + 4/5)))}{3(6-2)(2-7)}
\end{equation}
\end{quote}
\begin{minted}[]{racket}
(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5)))))
(* 3 (- 6 2) (- 2 7)))
\end{minted}
\begin{verbatim}
-37/150
\end{verbatim}
\subsection*{1.3}
\label{sec:org2df494f}
\begin{quote}
Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.
\end{quote}
Instead of searching for the two larger numbers, we just find the smallest. This way, we don't need to think about duplicate cases etc.
\begin{listing}[htbp]
\begin{minted}[]{racket}
(define (proc a b c)
(cond ((and (> a c) (> b c))
(+ (* a a) (* b b)))
((and (> a b) (> c b))
(+ (* a a) (* c c)))
((and (> b a) (> c a))
(+ (* b b) (* c c)))))
\end{minted}
\caption{\label{lst:orgdccc0fc}Sum of the two-out-of-three larger numbers}
\end{listing}
\begin{listing}[H]
\begin{minted}[]{racket}
<<larger-squares>>
(proc 4 2 3)
\end{minted}
\caption{Testing the previous procedure}
\end{listing}
\begin{verbatim}
25
\end{verbatim}
\subsection*{1.4}
\label{sec:orgccc8909}
\begin{quote}
Observe that our model of evaluation allows for combinations whose operators are compound expressions. Use this observation to describe the behavior of the following procedure:
\begin{minted}[]{racket}
(define (a-plus-abs-b a b)
((if (> b 0) + -) a b))
\end{minted}
\end{quote}
The operator to be used depends on the evaluation of the \texttt{if} statement.
\subsection*{1.5}
\label{sec:orgdcf3ac3}
\begin{quote}
Ben Bitdiddle has invented a test to determine whether the interpreter he is faced with is using applicative-order evaluation or normal-order evaluation. He defines the following two procedures:
\begin{minted}[]{racket}
(define (p) (p))
(define (test x y)
(if (= x 0)
0
y))
\end{minted}
Then he evaluates the expression
\begin{minted}[]{racket}
(test 0 (p))
\end{minted}
What behavior will Ben observe with an interpreter that uses applicative-order evaluation? What behavior will he observe with an interpreter that uses normal-order evaluation? Explain your answer. (Assume that the evaluation rule for the special form `if' is the same whether the interpreter is using normal or applicative order: The predicate expression is evaluated first, and the result determines whether to evaluate the consequent or the alternative expression.)
\end{quote}
The two cases are examined below:
\begin{itemize}
\item Applicative-Order evaluation
The interpreter will \emph{``evaluate the arguments and then apply''}, so it will first evaluate 0, then it will try to evaluate \texttt{(p)} which will result in an infinite loop. That is because in \mintinline{racket}{(define (p) (p))} \texttt{(p)}'s definition is itself.
\item Normal-Order evaluation
The interpreter will transform \mintinline{racket}{(test 0 (p))} to
\begin{minted}[]{racket}
(if (= 0 0)
0
(p))
\end{minted}
and then will evaluate the expression. Since \mintinline{racket}{(= 0 0)} evaluates to \mintinline{racket}{#t}, \texttt{(p)} will never be evaluated because it is not needed.
\end{itemize}
\subsection*{1.6}
\label{sec:orgb19b172}
\begin{quote}
Alyssa P. Hacker doesn't see why if needs to be provided as a special form. “Why can't I just define it as an ordinary procedure in terms of \texttt{cond}?” she asks. Alyssa's friend Eva Lu Ator claims this can indeed be done, and she defines a new version of if:
\begin{minted}[]{racket}
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
\end{minted}
Eva demonstrates the program for Alyssa:
\begin{minted}[]{racket}
(new-if (= 2 3) 0 5)
5
(new-if (= 1 1) 0 5)
0
\end{minted}
Delighted, Alyssa uses new-if to rewrite the square-root
program:
\begin{minted}[]{racket}
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
\end{minted}
What happens when Alyssa attempts to use this to compute
square roots? Explain.
\end{quote}
Since \texttt{new-if} is user-defined, all parameters will be evaluated before it is applied. Therefore, \mintinline{racket}{(sqrt-iter (improve guess x) x)} will always be evaluated, and since it calls itself it will run indefinitely.
\subsection*{{\bfseries\sffamily TODO} 1.7}
\label{sec:orged19a36}
\begin{quote}
The \texttt{good-enough?} test used in computing square roots will not be very effective for finding the square roots of very small numbers. Also, in real computers, arithmetic operations are almost always performed with limited precision. This makes our test inadequate for very large numbers. Explain these statements, with examples showing how the test fails for small and large numbers. An alternative strategy for implementing \texttt{good-enough?} is to watch how \texttt{guess} changes from one iteration to the next and to stop when the change is a very small fraction of the guess. Design a square-root procedure that uses this kind of end test. Does this work better for small and large numbers?
\end{quote}
\subsection*{1.8}
\label{sec:orge70c293}
\begin{quote}
Newton's method for cube roots is based on the fact that if \(y\) is an approximation to the cube root of \(x\), then a better approximation is given by the value
\begin{equation}
\frac{x/y^2 + 2y}{3}
\end{equation}
Use this formula to implement a cube-root procedure analogous to the square-root procedure. (In section 1-3-4 we will see how to implement Newton's method in general as an abstraction of these square-root and cube-root procedures).
\end{quote}
\begin{minted}[]{racket}
(define (cube x) (* x x x))
(define (good-enough? guess x)
(< (abs (- (cube guess) x)) 0.0000001))
(define (improve guess x)
(/ (+ (/ x (* guess guess)) (* 2 guess)) 3))
(define (cube-root-iter guess x)
(if (good-enough? guess x)
guess
(cube-root-iter (improve guess x) x)))
(define (cube-root x)
(cube-root-iter 1.0 x))
\end{minted}
\begin{minted}[]{racket}
<<cube-root>>
(cube-root 27)
\end{minted}
\begin{verbatim}
3.0000000000000977
\end{verbatim}
\end{document}