MIT 6.001 - Structure and Interpretation of Computer Programs: Notes and solutions

MIT 6.001 - Structure and Interpretation of Computer Programs: Notes and solutions #

SICP was revolutionary in many different ways. Most importantly, it dramatically raised the bar for the intellectual content of introductory computer science. Before SICP, the first CS course was almost always entirely filled with learning the details of some programming language. SICP is about standing back from the details to learn big-picture ways to think about the programming process. It focused attention on the central idea of abstraction – finding general patterns from specific problems and building software tools that embody each pattern. It made heavy use of the idea of functions as data, an idea that’s hard to learn initially, but immensely powerful once learned.

Why Structure and Interpretation of Computer Programs matters

I have read the Structure and Interpretation of Computer Programs nearly 20 years ago and I still remember it. Going through this book was intense and enlightening. It had a deep impact on how I would think about programming.

After 20 years, my work has moved me farther and farther from software engineering: managing teams, managing products, doing consulting works. In the last few years, I had the opportunity to see complex software being built, and I was disappointed at the lack of quality and the level of bugs in the code base.

Many seem to think that building high quality software takes more time and can’t be afforded. I can’t accept that. My belief is that quality software can be built not only faster, but cheaper than crappy software in the long run.

But at some point, you have to stop arguing for it and put your money where your mouth is. Well, this is my starting point. I plan to read the Structure and Interpretation of Computer Programs again, this time doing all the exercise. This is a just warmup before attacking more ambitious things.

I expect that by doing that I will:

  • become a better software engineer
  • aquire a deeper understanding of functional programming
  • have fun programming and building things
  • learn how to write clear explanation

This is the current plan:

  • Read the book
  • Watch the video from the 1986 session
  • Complete all the 356 exercises by myself, using DrRacket, and publish my solution here. Each solution should include clear explanations.
  • Review my solution and compare them to the community schemewiki SICP-Solutions or other solutions

These solutions are for reference only. The value of this book is in trying to solving each exercise. Please consider only checking solution after being stuck or after having solved the problem comparing your solution.

Table of Content #

Chapter 1: Building Abstractions with Procedures #

1.1 The Elements of Programming #

πŸ“Ί Lecture 1A: Overview and Introduction to Lisp - YouTube

1.1.1 Expressions #
1.1.2 Naming and the Environment #
1.1.3 Evaluating Combinations #
1.1.4 Compound Procedures #
1.1.5 The Substitution Model for Procedure Application #
1.1.6 Conditional Expressions and Predicates #
1.1.7 Example: Square Roots by Newton’s Method #
1.1.8 Procedures as Black-Box Abstractions #

1.2 Procedures and the Processes They Generate #

πŸ“Ί Lecture 1B: Procedures and Processes; Substitution Model - YouTube

1.2.1 Linear Recursion and Iteration #
1.2.2 Tree Recursion #
1.2.3 Orders of Growth #
1.2.4 Exponentiation #
1.2.5 Greatest Common Divisors #
1.2.6 Example: Testing for Primality #

1.3 Formulating Abstractions with Higher-Order Procedures #

πŸ“Ί Lecture 2A: Higher-order Procedures - YouTube

1.3.1 Procedures as Arguments #
1.3.2 Constructing Procedures Using Lambda #
1.3.3 Procedures as General Methods #
1.3.4 Procedures as Returned Values #

Chapter 2: Building Abstractions with Data #

2.1 Introduction to Data Abstraction #

πŸ“Ί Lecture 2B: Compound Data - YouTube

2.1.1 Example: Arithmetic Operations for Rational Numbers #
2.1.2 Abstraction Barriers #
2.1.3 What Is Meant by Data? #
2.1.4 Extended Exercise: Interval Arithmetic #

2.2 Hierarchical Data and the Closure Property #

πŸ“Ί Lecture 3A: Henderson Escher Example - YouTube

2.2.1 Representing Sequences #
  • Exercise 2.17
  • Exercise 2.18
  • Exercise 2.19
  • Exercise 2.20
  • Exercise 2.21
  • Exercise 2.22
  • Exercise 2.23
2.2.2 Hierarchical Structures #
  • Exercise 2.24
  • Exercise 2.25
  • Exercise 2.26
  • Exercise 2.27
  • Exercise 2.28
  • Exercise 2.29
  • Exercise 2.30
  • Exercise 2.31
  • Exercise 2.32
2.2.3 Sequences as Conventional Interfaces #
  • Exercise 2.33
  • Exercise 2.34
  • Exercise 2.35
  • Exercise 2.36
  • Exercise 2.37
  • Exercise 2.38
  • Exercise 2.39
  • Exercise 2.40
  • Exercise 2.41
  • Exercise 2.42
  • Exercise 2.43
2.2.4 Example: A Picture Language #
  • Exercise 2.44
  • Exercise 2.45
  • Exercise 2.46
  • Exercise 2.47
  • Exercise 2.48
  • Exercise 2.49
  • Exercise 2.50
  • Exercise 2.51
  • Exercise 2.52

2.3 Symbolic Data #

πŸ“Ί Lecture 3B: Symbolic Differentiation; Quotation - YouTube

πŸ“Ί Lecture 4A: Pattern Matching and Rule-based Substitution - YouTube

2.3.1 Quotation #
  • Exercise 2.53
  • Exercise 2.54
  • Exercise 2.55
2.3.2 Example: Symbolic Differentiation #
  • Exercise 2.56
  • Exercise 2.57
  • Exercise 2.58
2.3.3 Example: Representing Sets #
  • Exercise 2.59
  • Exercise 2.60
  • Exercise 2.61
  • Exercise 2.62
  • Exercise 2.63
  • Exercise 2.64
  • Exercise 2.65
  • Exercise 2.66
2.3.4 Example: Huffman Encoding Trees #
  • Exercise 2.67
  • Exercise 2.68
  • Exercise 2.69
  • Exercise 2.70
  • Exercise 2.71
  • Exercise 2.72

2.4 Multiple Representations for Abstract Data #

πŸ“Ί Lecture 4B: Generic Operators - YouTube

2.4.1 Representations for Complex Numbers #
2.4.2 Tagged data #
2.4.3 Data-Directed Programming and Additivity #
  • Exercise 2.73
  • Exercise 2.74
  • Exercise 2.75
  • Exercise 2.76
  • Exercise 2.77

2.5 Systems with Generic Operations #

2.5.1 Generic Arithmetic Operations #
  • Exercise 2.78
  • Exercise 2.79
  • Exercise 2.80
2.5.2 Combining Data of Different Types #
  • Exercise 2.81
  • Exercise 2.82
  • Exercise 2.83
  • Exercise 2.84
  • Exercise 2.85
  • Exercise 2.86
2.5.3 Example: Symbolic Algebra #
  • Exercise 2.87
  • Exercise 2.88
  • Exercise 2.89
  • Exercise 2.90
  • Exercise 2.91
  • Exercise 2.92
  • Exercise 2.93
  • Exercise 2.94
  • Exercise 2.95
  • Exercise 2.96
  • Exercise 2.97

Chapter 3: Modularity, Objects, and State #

πŸ“Ί Lecture 5A: Assignment, State, and Side-effects - YouTube

3.1 Assignment and Local State #

3.1.1 Local State Variables #
  • Exercise 3.1
  • Exercise 3.2
  • Exercise 3.3
  • Exercise 3.4
3.1.2 The Benefits of Introducing Assignment #
  • Exercise 3.5
  • Exercise 3.6
3.1.3 The Costs of Introducing Assignment #
  • Exercise 3.7
  • Exercise 3.8

3.2 The Environment Model of Evaluation #

3.2.1 The Rules for Evaluation #
3.2.2 Applying Simple Procedures #
3.2.3 Frames as the Repository of Local State #
  • Exercise 3.9
  • Exercise 3.10
3.2.4 Internal Definitions #
  • Exercise 3.11

3.3 Modeling with Mutable Data #

πŸ“Ί Lecture 5B: Computational Objects - YouTube

3.3.1 Mutable List Structure #
  • Exercise 3.12
  • Exercise 3.13
  • Exercise 3.14
  • Exercise 3.15
  • Exercise 3.16
  • Exercise 3.17
  • Exercise 3.18
  • Exercise 3.19
  • Exercise 3.20
3.3.2 Representing Queues #
  • Exercise 3.21
  • Exercise 3.22
  • Exercise 3.23
3.3.3 Representing Tables #
  • Exercise 3.24
  • Exercise 3.25
  • Exercise 3.26
  • Exercise 3.27
3.3.4 A Simulator for Digital Circuits #
  • Exercise 3.28
  • Exercise 3.29
  • Exercise 3.30
  • Exercise 3.31
  • Exercise 3.32
3.3.5 Propagation of Constraints #
  • Exercise 3.33
  • Exercise 3.34
  • Exercise 3.35
  • Exercise 3.36
  • Exercise 3.37

3.4 Concurrency: Time Is of the Essence #

3.4.1 The Nature of Time in Concurrent Systems #
  • Exercise 3.38
3.4.2 Mechanisms for Controlling Concurrency #
  • Exercise 3.39
  • Exercise 3.40
  • Exercise 3.41
  • Exercise 3.42
  • Exercise 3.43
  • Exercise 3.44
  • Exercise 3.45
  • Exercise 3.46
  • Exercise 3.47
  • Exercise 3.48
  • Exercise 3.49

3.5 Streams #

πŸ“Ί Lecture 6A: Streams, Part 1 - YouTube

πŸ“Ί Lecture 6B: Streams, Part 2 - YouTube

3.5.1 Streams Are Delayed Lists #
  • Exercise 3.50
  • Exercise 3.51
  • Exercise 3.52
3.5.2 Infinite Streams #
  • Exercise 3.53
  • Exercise 3.54
  • Exercise 3.55
  • Exercise 3.56
  • Exercise 3.57
  • Exercise 3.58
  • Exercise 3.59
  • Exercise 3.60
  • Exercise 3.61
  • Exercise 3.62
3.5.3 Exploiting the Stream Paradigm #
  • Exercise 3.63
  • Exercise 3.64
  • Exercise 3.65
  • Exercise 3.66
  • Exercise 3.67
  • Exercise 3.68
  • Exercise 3.69
  • Exercise 3.70
  • Exercise 3.71
  • Exercise 3.72
  • Exercise 3.73
  • Exercise 3.74
  • Exercise 3.75
  • Exercise 3.76
3.5.4 Streams and Delayed Evaluation #
  • Exercise 3.77
  • Exercise 3.78
  • Exercise 3.79
  • Exercise 3.80
  • Exercise 3.81
  • Exercise 3.82

Chapter 4: Metalinguistic Abstraction #

4.1 The Metacircular Evaluator #

πŸ“Ί Lecture 7A: Metacircular Evaluator, Part 1 - YouTube

4.1.1 The Core of the Evaluator #
  • Exercise 4.1
4.1.2 Representing Expressions #
  • Exercise 4.2
  • Exercise 4.3
  • Exercise 4.4
  • Exercise 4.5
  • Exercise 4.6
  • Exercise 4.7
  • Exercise 4.8
  • Exercise 4.9
  • Exercise 4.10
4.1.3 Evaluator Data Structures #
  • Exercise 4.11
  • Exercise 4.12
  • Exercise 4.13
4.1.4 Running the Evaluator as a Program #
  • Exercise 4.14
4.1.5 Data as Programs #
  • Exercise 4.15
4.1.6 Internal Definitions #
  • Exercise 4.16
  • Exercise 4.17
  • Exercise 4.18
  • Exercise 4.19
  • Exercise 4.20
  • Exercise 4.21
4.1.7 Separating Syntactic Analysis from Execution #
  • Exercise 4.22
  • Exercise 4.23
  • Exercise 4.24

4.2 Variations on a Scheme-Lazy Evaluation #

πŸ“Ί Lecture 7B: Metacircular Evaluator, Part 2 - YouTube

4.2.1 Normal Order and Applicative Order #
  • Exercise 4.25
  • Exercise 4.26
4.2.2 An Interpreter with Lazy Evaluation #
  • Exercise 4.27
  • Exercise 4.28
  • Exercise 4.29
  • Exercise 4.30
  • Exercise 4.31
4.2.3 Streams as Lazy Lists #
  • Exercise 4.32
  • Exercise 4.33
  • Exercise 4.34

4.3 Variations on a Scheme-Nondeterministic Computing #

  • Exercise 4.35
  • Exercise 4.36
  • Exercise 4.37
4.3.2 Examples of Nondeterministic Programs #
  • Exercise 4.38
  • Exercise 4.39
  • Exercise 4.40
  • Exercise 4.41
  • Exercise 4.42
  • Exercise 4.43
  • Exercise 4.44
  • Exercise 4.45
  • Exercise 4.46
  • Exercise 4.47
  • Exercise 4.48
  • Exercise 4.49
4.3.3 Implementing the Amb Evaluator #
  • Exercise 4.50
  • Exercise 4.51
  • Exercise 4.52
  • Exercise 4.53
  • Exercise 4.54

4.4 Logic Programming #

πŸ“Ί Lecture 8A: Logic Programming, Part 1 - YouTube

πŸ“Ί Lecture 8B: Logic Programming, Part 2 - YouTube

4.4.1 Deductive Information Retrieval #
  • Exercise 4.55
  • Exercise 4.56
  • Exercise 4.57
  • Exercise 4.58
  • Exercise 4.59
  • Exercise 4.60
  • Exercise 4.61
  • Exercise 4.62
  • Exercise 4.63
4.4.2 How the Query System Works #
4.4.3 Is Logic Programming Mathematical Logic? #
  • Exercise 4.64
  • Exercise 4.65
  • Exercise 4.66
  • Exercise 4.67
  • Exercise 4.68
  • Exercise 4.69
4.4.4 Implementing the Query System #
  • Exercise 4.70
  • Exercise 4.71
  • Exercise 4.72
  • Exercise 4.73
  • Exercise 4.74
  • Exercise 4.75
  • Exercise 4.76
  • Exercise 4.77
  • Exercise 4.78
  • Exercise 4.79

Chapter 5: Computing with Register Machines #

5.1 Designing Register Machines #

πŸ“Ί Lecture 9A: Register Machines - YouTube

  • Exercise 5.1
5.1.1 A Language for Describing Register Machines #
  • Exercise 5.2
5.1.2 Abstraction in Machine Design #
  • Exercise 5.3
5.1.3 Subroutines #
5.1.4 Using a Stack to Implement Recursion #
  • Exercise 5.4
  • Exercise 5.5
  • Exercise 5.6
5.1.5 Instruction Summary #

5.2 A Register-Machine Simulator #

πŸ“Ί Lecture 9B: Explicit-control Evaluator - YouTube

  • Exercise 5.7
5.2.1 The Machine Model #
5.2.2 The Assembler #
  • Exercise 5.8
5.2.3 Generating Execution Procedures for Instructions #
  • Exercise 5.9
  • Exercise 5.10
  • Exercise 5.11
  • Exercise 5.12
  • Exercise 5.13
5.2.4 Monitoring Machine Performance #
  • Exercise 5.14
  • Exercise 5.15
  • Exercise 5.16
  • Exercise 5.17
  • Exercise 5.18
  • Exercise 5.19

5.3 Storage Allocation and Garbage Collection #

πŸ“Ί Lecture 10B: Storage Allocation and Garbage Collection - YouTube

5.3.1 Memory as Vectors #
  • Exercise 5.20
  • Exercise 5.21
  • Exercise 5.22
5.3.2 Maintaining the Illusion of Infinite Memory #

5.4 The Explicit-Control Evaluator #

5.4.1 The Core of the Explicit-Control Evaluator #
5.4.2 Sequence Evaluation and Tail Recursion #
5.4.3 Conditionals, Assignments, and Definitions #
  • Exercise 5.23
  • Exercise 5.24
  • Exercise 5.25
5.4.4 Running the Evaluator #
  • Exercise 5.26
  • Exercise 5.27
  • Exercise 5.28
  • Exercise 5.29
  • Exercise 5.30

5.5 Compilation #

πŸ“Ί Lecture 10A: Compilation - YouTube

5.5.1 Structure of the Compiler #
  • Exercise 5.31
  • Exercise 5.32
5.5.2 Compiling Expressions #
5.5.3 Compiling Combinations #
5.5.4 Combining Instruction Sequences #
5.5.5 An Example of Compiled Code #
  • Exercise 5.33
  • Exercise 5.34
  • Exercise 5.35
  • Exercise 5.36
  • Exercise 5.37
  • Exercise 5.38
5.5.6 Lexical Addressing #
  • Exercise 5.39
  • Exercise 5.40
  • Exercise 5.41
  • Exercise 5.42
  • Exercise 5.43
  • Exercise 5.44
5.5.7 Interfacing Compiled Code to the Evaluator #
  • Exercise 5.45
  • Exercise 5.46
  • Exercise 5.47
  • Exercise 5.48
  • Exercise 5.49
  • Exercise 5.50
  • Exercise 5.51
  • Exercise 5.52

Resources #

Book #

Videos #

Other #

Other solutions #

  • Structure and Interpretation of Computer Programs: “This repository includes answers to a bit more than 90% of the book’s 360-some exercises as well as material intended to help others get an idea of how to begin with the book, avoid many common pitfalls as they continue, and review interesting secondary material along the way.”

Tools used #

  • Episode 503: Robert Martin on Structure and Interpretation of Computer Programming
    • “It changed the way I look at the fundamental structure of programs. It is possible, and desirable, to write code without assignement statements as much as possible. To not mutate the states of variables. And it forces you to think about software in a very different way. […] I assign now variable less frequently.”
    • “[functional programming] forces you to keep your data in much better order. There will always be times when you have to change the state of the system but you do so with a tremendous amount of discipline in this language. You treat the changing of data in the system the way you would treat a transaction on disk.”

What next? #