What I took from SICP is something, no one else and no other ressource has taught me and it has enabled me to start a long possibly never ending journey of learning. I will be forever thankful for having learned the lessons I took from it. I think I would be half the engineer I am today, if I had not read and worked through the part of SICP, that I did work and read through.
What I use most of those in my software development: Avoiding mutation when affordable and feasible (which is often), proper abstraction barriers and modularization, thinking about functions and how to compose them and solve problems with them, instead of going "I heard a noun, I need a class!", how to solve problems recursively (although The Little Schemer did have a hand in teaching that as well), and some kind of idea of minimalism.
Aside from all that, SICP has shown me a different way to learn about math stuff. It has shown me, that there is a way, in which I understand math better than in university lectures. That way is through computer programming. If I can write the code for it and explain what the code does, I usually can also understand the math.
> there is a way, in which I understand math better than in university lectures. That way is through computer programming.
Do you have examples of mathematical concepts that you developed an understanding of this way?
It is not exactly the same thing but it reminds me of a 1986 interview with David Blackwell[1] in which he went into great detail about how computers helped his own mathematical learning:
I have a little computer at home, and it's a lot of fun just to play with it. [...] Jim MacQueen was telling me about something that he had discovered. [...] He has an interesting algebraic identity. [...] Also, I had a conjecture that some stronger result was true. I checked it for some numbers selected at random and it turned out to be true for him and *not* true for what I had said. Well, that just settles it.
You may be interested in the ideas in Papert's book Mindstorms and the application of Logo to education through "microworlds". Given rules and systems to work within (or possibly to define themselves), students are given the opportunity to explore the systems and the way things interact. Most people only seem to remember Logo for its turtle graphics, which allows an exploration of geometric and (through the connection of geometry and algebra) algebraic concepts. But there were also microworlds for physics (dynaturtles) and others.
> Most people only seem to remember Logo for its turtle graphics
i got taught a tiny bit of logo in elementary school - just the very basics of moving the turtle, drawing a straight line, turning an angle, and drawing polygons.
The final challenge of the class was to draw a circle. It blew my mind when i figured it out.
I suspect that must be the inception of my love for programming.
I really wish schools would offer various ways to reach for a concept. In programming, as college students, it's not rare to understand an idea better through use of different paradigms. It seems an efficient way to tickle the brain.
After SICP Sussman wrote Structure and Interpretation of Classical Mechanics. The text is available free online, and it covers some (advanced) areas of classical mechanics by way of simulation.
Another interesting piece he wrote is The Art of the Propagator, which is also freely available. His CSAIL page has more of his publications: https://groups.csail.mit.edu/mac/users/gjs/
Slightly off topic but how did you find a group of people to do this with? I’d love to but I can’t imagine anyone in my social circles/work acquaintances doing this with any book.
...and an IRC channel. The wiki wasn't much used, IRC was where everything happened. I think the way to do it today would be a discord server, and you need more people than you think to start; they will drop off fast.
While in the end captures variables and classes might be equivalent, captured variables seem low-fat while a class is usually instantiated (otherwise please use a struct, enum, record, namespace, ...) and comes with usually mutable members. Setting them in a non-mutating functional way would probably require to create a whole new instance of the class (object). Often a class is an overkill of a concept for something simpler hiding in it (like a record or struct) and too many people do not think about making things simpler once they typed the word class.
A function on the other hand forces one to think of function calls and not some kind of state that was set earlier, splitting time in parts of before setting that state on an object and after. A function (when using the term more strictly) will always give the same result for the same input. I get more guarantees about my program than I get when classes and instances of them are mutated.
Recursion can solve problems very elegantly at times. When I use it in other non-TCO languages, I always think about stack depth and consider externalizing the stack as an option.
One thing mathematical, that I understood much better through SICP was hiw Church numerals work and how they could serve as numbers in theory. Another one was derivatives, since one writes a symbolic calculation of derivatives in SICP. Then the Newton method for finding zeroes. Basically any such topic, that one needs to implement in the exercises of SICP, because one has to get familiar with how it works more, in order to implement it.
https://github.com/MoserMichael/jscriptparse - this is my pet project, it's an educational / shell scripting language. It tries to allow for concise expression, and you have a REPL/shell.
Ideally I want to fit this niche as well, where you can solve these problems in a concise manner (well, maybe slightly more concise than python or javascript, and with a subset of the features that you would expect with a programming language for grown ups)
I like the "What I learned" section. Maybe I should steal that idea for my own projects, even if only for my future self and maybe to put in words any revelations I had during development. One could even think about putting all kinds of thoughts and conclusions into such a document or a separate section of the readme.
another thing, closures acts as anonymous classes, and partial application yields naturally safe linear state sequences.
f a -> b -> c
you get three steps until all information is known and computation can happen
you didn't have to define anything, didn't have to think about it, while in OOP you'd have
class F:
setA
setB
setC
logicThatCanBeCalledAnytime
here you either get a random logic with unknown a,b,c state
or to think very carefully what states things should be
or design safeguards around every methods to ensure things are known... (and AFAIK no mainstream OO language even makes an attempt at having metalevel state transition checks easy to define and ensure..)
Most dynamic languages including Scheme have unlimited recursion (limited only by total memory).
Once you've gotten used to being able to use recursion, stack depth limits seem as lame as olden-days limits on string length (255 characters was common in Pascal).
Javascript is a frustrating case where unlimited recursion is technically possible in modern engines, but they still often limit it to 10000 or something.
Python limits it arbitrarily, just to force you to use its fancy iteration system.
> Python limits it arbitrarily, just to force you to use its fancy iteration system.
Python has an arbitrary and low default limit because it isn’t optimized (because stack traces are considered important), abd call depth is an effifiency issue that risks blowing up without a limim because of stack depth, and failing fast in the likely-erroneous case of deep call stack given all that is just sensible. Python also. Lets you alter the limit at runtime; ita a soft, not hard, limit. The hard limit is stack space.
People often talk about accidental infinite recursion, but that seems like a rare mistake. I might have done it twice in a 40 year career? It's much rarer than an accidental infinite loop, which (almost) no language tries to protect you against. It doesn't seem worth giving up useful recursion.
Python's "solution" requires changing a global, which is an ugly thing for a library that wants to recurse to do.
You or the code you write must be extremely unusual. I might have blown the stack a thousand times, in many different languages. Probably most of the time I wasn't intentionally recursing at all.
It’s not quite arbitrarily. That’s an uncharitable definition. Python a) handles function arguments in a way that would make recursive functions awkward to use and b) cares about stacktraces being meaningful, so TCO would be a worse tradeoff towards that end as well.
There’s trampolines in almost any programming language to implement recursion if necessary, and python has itertools to build what Scheme calls streams, for arbitrary computation.
>And recursions are no fun, when you run out of stack space.
It's been a while since I read anything about this topic but they get optimized out by the compiler in most cases, right?
You are probably thinking of tail-call optimization, which is when a recursive function returns the result of calling itself as its last action. These algorithms and functions are called tail-recursive.
Compilers and interpreters can (more easily) optimize tail-recursive algorithms to avoid the normal cost of creating a new stack frame and making a normal function call, which means the recursive algorithm has performance more like that of an iterative implementation.
That is possible, if the recursion call is the last statement of the recursive function (tail call optimization). Now the recursion call is not always at the end of the function, so that this optimization does not always apply. https://en.wikipedia.org/wiki/Tail_call
Now Python doesn't do tail call optimization out of the box (surprise). but there is a module that is adding some magical decorator that fixes that: https://pypi.org/project/tail-recursive/
(actually need to look how they implement this decorator, it must be some serious hack.)
You can do tail call optimisation when the last thing you do before you return is a call. That tail call is not necessarily recursive, let alone a call to yourself. Whatever it is, its position means your current stack-frame can be reclaimed before you jump.
If you can only optimise calls to yourself, you have a very limited form of tail call optimisation. It's an important point in the context of Scheme, where they made a big deal out of experimenting with continuation passing style. In CPS, all function calls are tail calls, and you want to optimise them all, even though most are not recursive.
Not usually, no. Some languages support automatic tail-call optimization (when a recursive call is the returned value of a function, you can effectively replace the current stack with the recursively-called one), but in general, there are limits to how "sufficiently-advanced" real compilers are.
Eliminating recursion might be difficult to detect if multiple functions form a mutually-recursive set, or if data structures have to be introduced to compensate for no stack (e.g., converting a depth-first search from recursive to iterative form requires a stack).
I never understood newtonian mechanics taught in high school physics until I wrote a simulator for it. The code is generally ~100 lines in python but you really get the feel for how the equations work.
There is a reason Newtonian Physics was invented and found huge success throughout the 1600s and 1700s. It's such a simple framework that a wide variety of consequences can be obtained by just playing with the equations by hand, even without a calculator. They are just linear first and second order differential equations.
All the questions you asked while writing the code, can be asked to the equations and the consequences worked out almost immediately.
What I use most of those in my software development: Avoiding mutation when affordable and feasible (which is often), proper abstraction barriers and modularization, thinking about functions and how to compose them and solve problems with them, instead of going "I heard a noun, I need a class!", how to solve problems recursively (although The Little Schemer did have a hand in teaching that as well), and some kind of idea of minimalism.
Aside from all that, SICP has shown me a different way to learn about math stuff. It has shown me, that there is a way, in which I understand math better than in university lectures. That way is through computer programming. If I can write the code for it and explain what the code does, I usually can also understand the math.