Hacker News new | past | comments | ask | show | jobs | submit login
Composing Programs – An introduction to programming in the tradition of SICP (composingprograms.com)
155 points by jxub 7 months ago | hide | past | web | favorite | 53 comments

I still don't understand why after so many years people are still trying to write a "SICP, but with language X".

"The language doesn't really matter", as such it's imperative Scheme is used.

I strongly feel that if you've worked your way through SICP, and, once finished, you think "Neat. I'll rewrite this but with language X," you've really missed out on value of SICP.

It's challenging enough to follow for people who know a Lisp going in, but using a language more mainstream and familiar to make it easier is largely counter-productive.

I'd rather see a SICP rewrite that lowers the barriers of mathematical pre-requisites. SICP is a great book but I found myself having to research calculus equations more than I'd like.

Appreciate someone else mentioning it. As a self taught dev, with pretty poor Math skills, it was frustrating hitting parts refering to some equation you are just supposed to know. Totally derailed my learning having to understand some random equation that wasn’t fully relevant

How To Design Programs covers some of the same ground. (It's also in a lisp)

As somebody who's always been strong in math, I agree. For the MIT crowd it can be a reasonable expectation, but in general an introductory course in Topic A should not require advanced & unrelated Topic B knowledge.

I think I fail to understand your somewhat poetic and evocative language, I'm afraid that I'm going to ask you to dumb it down for me:

>"The language doesn't really matter", as such it's imperative Scheme is used.

This is an obvious contradiction and clearly you meant it that way but what do you imply exactly?

>I strongly feel that if you've worked your way through SICP, and, once finished, you think "Neat. I'll rewrite this but with language X," you've really missed out on value of SICP.

>It's challenging enough to follow for people who know a Lisp going in, but using a language more mainstream and familiar to make it easier is largely counter-productive.

You claim that using an other language for SICP is "[missing] out on value" and "largely counter-productive" but you don't produce any evidence or argument to support that.

Going through SICP using a static and non-reflective language like C does seem very frustrating but using a very dynamic language like Python might indeed be a decent fit. At least I can't see what's so obviously wrong about it.

I am not craigsmansion, but I think I know what he or she meant. The lessons in SICP are about fundamental computing concepts and independent of any language. The authors simply chose Scheme because it is easy to learn and let them teach those lessons comfortably.

This means that rewriting it using a different language is mostly a waste of time: it's not a very short book, so rewriting takes a while and what is gained? It seems to me that, at most, you learn that specific language in addition to the fundamental concepts. I personally, would not think that is worth the effort.

> The lessons in SICP are about fundamental computing concepts and independent of any language. The authors simply chose Scheme because it is easy to learn and let them teach those lessons comfortably.

Exactly, And for some of their audience they may already be more familiar with a different language -- so why not lower the barrier of entry?

As someone who just picked up SICP to see what the big deal was, I think that the choice of Scheme actually does add something: the ridiculously minimal syntax adds a kind of clarity, making it clear that things you thought were fundamental aspects of programming are really just language features. There is so little syntax to learn that virtually everything you learn is a lesson in program structure - because there's barely a "language" at all.

I was already familiar with Python when I started SICP, and the simple syntax caused a kind of fundamental shift in perspective. I had absolutely no idea how the Python parser worked. I couldn't model it in my head. I just knew that there were all these special things - methods, loops, iterators - and I could try and reason about how they'd work together, but I didn't really have a mental model of what was going on.

Scheme, in contrast, was so simple that they tell you more-or-less how the parser works in the very first chapter. I solved many of the first chapter's exercises on paper. I couldn't - and still can't - imagine running a Python program with paper and pencil. For the very first time in my life, I actually had a mental model of what exactly my code was doing.

And the super-minimal syntax made so many things I'd understood as totally distinct atomic concepts could actually be treated as related. The shift from f(x) to (f x) was a transposition of a single character - but it actually changed the way I was looking at the concept. f(x) was static - you specified a particular f, and applied your choice of x. (f x) - and suddenly f and x are objects of similar status. Expand and evaluate the element on the left. Expand and evaluate the element(s) on the right. Plug the stuff on the right into the stuff on the left. They follow the same rules! You can have (f (+ x y)) sure, but you could have the f as a compound procedure too! Or on the question of loops and recursion - loops had always been something I understood as a particular special construct, totally unrelated to recursion. Then - oh. Of course. They're both just ways of calling the same procedure multiple times. They're both recursion, just with different structures.

Basically, I think Scheme is serving two purposes here. The first - everyone learns assumptions from their first programming language. That's why you should always learn a second one, ideally a quite different one, just so you can see how there can be entirely different ways of thinking about and structuring the same concepts. So a language that's nobody uses is actually the perfect language to teach how to Structure and Interpret Computer Programs, because it helps you get past the pre-existing assumptions you'd unknowingly picked up about how to do that.

And secondly, because the syntax is so simple that it helps you really, clearly understand what your program is doing, what various ways of doing things mean. I hadn't even realized before picking up SICP that "learning to program" was a distinct skill from "learning how to code." They were the same thing - you learn the programming language, and then you just use the tools it gives you. Not knowing how to write something to solve a problem was mostly just an issue of not knowing the features of the language, or the available libraries, well enough.

In the first chapter, I was introduced to a simple subset of an already simple language. It was just parentheses, definitions, and conditionals, and a set of expansion and substitution rules basic enough I could work them out on paper. I didn't even have loops or lists. And it became suddenly clear that while I'd taught myself to code from reading language tutorials and the excellent Python documentation, I had never actually learned how to program.

So what I'm saying is, as an amateur programmer who was familiar with Python and not much else, I'm extremely glad that they chose to write it in Scheme instead of Python.

I see what you mean but I don't think it justifies "as such it's imperative Scheme is used". I'm by no means a fan of Python but its syntax not much more complex than that of a lisp and on top of that it supports infix notation which will probably be easier to write and read for beginners since it more closely matches the mathematical notation they're undoubtedly already familiar with. Even the function evaluation matches mathematics better: f(x) instead of (f x).

Rewriting SICP using Python instead of lisp does seem like a rather boring and thankless job but I'm not sure that reading through SICP in Python would be much worse than using Scheme.

> This is an obvious contradiction and clearly you meant it that way but what do you imply exactly?

If you take "not matter" literally, you could derive that the more a language "matters" (has real-world applications), the worse it would fit. It could be argued that Scheme does not matter for the real world, and as such should be the perfect fit.

More seriously, Scheme is very small. Everything is done by what technically could be described as implementing a Domain Specific Language (DSL). It could be argued that any program in any language is just a DSL for solving a particular problem. If the language doesn't matter, then any language will do, and Scheme with its natural DSL-like approach is very close to the ideal "any language".

> You claim that using an other language for SICP is "[missing] out on value" and "largely counter-productive" but you don't produce any evidence or argument to support that.

Every language, including all Lisps, at some level reflect the machine or model it runs on. This creates a bias of "how things are/work".

SICP goes through great lengths to undo that: "This is how you think X works. That's not how it works. It also doesn't matter how it works, because the concept we're discussing is valid either way. So stop thinking about these details."

The fewer preconceptions you have about what you think is "programming," the better it is for understanding what the lectures are about. If you go in knowing a Lisp, it's easy to miss what they're talking about because it invites you to , being already familiar with the syntax, assume it's about the language when it's not.

This contradicts a "SICP for Python programmers."

So "SICP for Python programmers" is really the normal "SICP", which in turn should be called "SICP for all programmers except Lispers" with them losing out because there's really no better language to express the ideas behind SICP in so they might as well use SICP and try to hold their bias in check.

For what it's worth, I feel like we already have a version of that book by Peter Norvig:


I even ported the "Simulator for digital circuits" from SICP in Java (which "slightly" differs from Scheme): https://github.com/vandekeiser/wires (look at the wires-core module).

What I like about this book and "The little schemer" is how it is possible to "program in your head" with the examples. Maybe it is due to the homoiconicity?

I'm not sure if you are arguing that the language matters or not, but isn't one the exercises to implement a Lisp interpreter? Changing this to another language would make the task much harder if not practically impossible.

Maybe I came to SICP too late in life, but I've always struggled to get the hype. It seems so... Basic. Making a linked list is trivial in lisp. Lisp itself is trivial. Why does everyone care about this book so much?

> Lisp itself is trivial.

Anything about an actual programming language is trivial in the book. I think by design.

In a way, the book isn't even really using the Scheme language. It uses a seemingly makeshift language to help decompose a thought-process into uniform and logical elements. Then, if you throw some syntax at it (using a bunch of parenthesis), you can actually make a computer execute your thought process, almost as a convenient coincidence (which is also why the actual language doesn't matter. It's just that all other languages are more cluttered when trying to capture the concepts of the thought-processes as presented).

One of the stated goals in the book is to blur the line between procedures and data. I believe that if you do SICP well, it blurs the line between data, procedures, and conceptual thought. If you can express a thought well enough to give it a name, to "define" it, you can control it (or "them", depending on whether you are depending on a procedure or spirits to do your bidding).

You don't walk away from SICP an expert Lisp programmer. You walk away from SICP wondering if yin-yang is a fun joke by the authors, some weird coincidence, or actually a governing principle of a Universe which itself is written in Lisp.

You also walk away wondering why people insist on calling OO a "paradigm".

Thanks for your response. I can see how others can find value in the book now. The answer is that I'd already come away with those concepts long before the book, so the simplicity of the book belied its value.

It doesn't just make a linked list, if I remember right it goes through a whole compiler along with using continuations to implement a type of programming where every possibility is followed until it succeeds, along with several other paradigms.

I am not sure whether you're joking, or a programming wizard, no disrespect intended. I run courses in programming languages where very smart kids struggle with streams (Section 3.5). I find the code for the Hamming Problem and Eratosthenes' Sieve using streams truly mind-expanding.


Myself after working through chapters upto 4(I think), did find it full of brilliant exposition of a few approaches to solve a bunch of interesting problems, but I did get a feeling that most of these methods aren't going to directly help with writing real world programs to solve the problems encountered in the wild. To put it in a vague analogy felt like reading a math book that has detailed explanations of brilliant proofs of select theorems, but doesn't fully explain how the proofs were arrived at from scratch, and doesn't describe general methods to discover proofs for as yet unknown problems. "Concepts, Techniques and Models of Computer Programming" Van Roy and Haridi, in premise sort of tries to cover that, aiming to describe a sort of 'science of programming', I haven't read too far into the book yet to comment if it delivers on that.

It took me many months to work through the book with exercises, and I found it quite challenging. Maybe I'm not the sharpest knife in the drawer, but I was already a developer with many years of practical experience at the time. Didn't have a CS background at the time though - maybe it would be easy if you already know all the theory.

I agree Scheme is pretty easy to learn, that was not the challenging part of the book. Exercises like implementing a logic language were pretty challenging, not to mention the math.

I don't remember Lisp or linked lists being an important part of the book. Yeah, you'll deal with them a lot because it's using Scheme, but that's really not the main point.

I used it to get started with CS as a programmer who didn't study CS in college. I thought it was pretty good. It assumes the reader is intelligent. A lot of books and tutorials do way too much hand-holding for my taste.

It's an intro book. If you've already done CS in college I don't expect you'd find it very insightful.

The book covers interpreters, compilers, non-deterministic and logic programming (including a implementation of a subset of prolog, using continuations). It's not that basic.

That's the point Hal Abelson makes in the first lecture of the class he taught off SICP. That's all there is to Lisp, just like you can teach someone chess in 10 minutes. SICP is about becoming a grandmaster.

In my opinion, Scheme is not a good first-language to learn for beginners or for anyone getting into programming. Why?

Because if you take an introductory CS course taught in Scheme, and you decide the field isn't for you, then you have essentially wasted a semester learning something you'll never use.

Compare this to Python, which is general enough to transfer to other domains (with its numerous libraries) and is way easier to pick up. In addition, its near resemblance to English is friendlier to approach. I'm sure there are some plots out there showing the number of companies which use Python versus Scheme.

This was the intuition, I believe, of why Berkeley for its 61A course switched from using Scheme as its primary language to using mostly Python and Scheme as a secondary language. (You still learn enough Scheme in the course to be able to build a Python interpreter for it).

TL;DR - the language does matter; the first one shapes how one views CS; save Scheme as a later language to be used to shape mental models.

tangential question - inn the left nav of this page there is a link for "CS 61A: Structure and Interpretation of Computer Programs" with videos, slides and lectures. The URL is:


However the syllabus begins at week 7. Does anyone know where to find the first 5 weeks of this class? Also does anyone know what school this affiliated with?

Scroll down a little and you'll see a table with the materials of the previous weeks. It goes like Introduction, Functions, Data etc. Paradigms is the current one - Week 7.

It displays week 7 at the top right now because that's the point the students taking the course at Berkeley have reached this semester.

The table below includes all weeks.

Thanks, now I feel silly :)

A friend of mine is approaching programming (very beginner level) through JavaScript. Is there any resource you would suggest in the same vein of this?

EDIT: since people are asking, I agree that JS is not the best language to get started, but let's just say he needs to learn that.

This might be of interest: https://www.comp.nus.edu.sg/~cs1101s/sicp/ (SICP in js)

Not a direct equivalent, but I've frequently seen people recommend https://eloquentjavascript.net/

Seconding this recommendation.

I would suggest absolutely not learning programming via javascript as your first language.

I agree that javascript is a bit odd for a beginner in terms of scoping, callbacks, truthiness, etc. However, it's really broadly applicable, JS would be a horrible choice for a university introductory course but might not be a bad choice for a hobbyist who's trying to quickly start doing things that keep them interested in learning.

I would however, strong suggest that javascript shouldn't be someone's only language.

Python has the same scoping as JS. I really don’t get why people complain about this then propose python as an alternative. JS even got past that with let/const.

In JS, declaring a variable without var gives it a global scope, in python not so.

Also, js is a lot more inconsistent than python. The amount of js gotchas is huge(== weirdness, hasOwnProperty for iterating through object fields, binding of this, only 64 bit doubles as a number type). Python is much less surprising, and gives you much less opportunities to screw up.

As a sibling to my other comment: Python is not less surprising, when programming in a JS style.

`nonlocal` is crazy. That lambdas may only be a single line is annoying. Being unable to print anything out of a map or filter operation without first converting to a list gets tedious quick. And not being able to go in for a quick monkey patch on repr, because builtin classes are magically different than user defined classes in “some way”, which makes modifying them prohibited, is limiting.

Sure, the easy retort is: that’s not what you should be doing anyways, python just enforces it. But I’d personally hate to see such an argument in the comment section of SICP, the pinnacle of programmer freedom.

Edit: and what about mutable default parameters?? I’ve had a fair amount of experience with python and sill been bitten by a mutable default parameter bug (not quite that, but related) in the past couple months. JS gets rid of that entirely by making them just syntactic sugar for what it would do anyways, which is much easier to reason about.

The bug I had was declaring variables in the body of a class without `self.`. Turns out that makes them static. Ironically similar to JS making non prefixed declarations global, except I received no in editor warnings about that, and it wasn’t something beaten into my head from the day I started.

Edit: or was it that I initialized them at time of declaration rather than in the constructor? Not sure. Something along those lines.

Most of the issues I find people annoyed with in JS are becoming less of an issue with modern idiomatic JS that is less object oriented, more functional and with ES6 utilities replacing more troublesome legacy idioms. I work on a fairly large app that uses little no classes. Also, I haven't had to use hasOwnProperty in a year! I just use Object.keys()

That’s a strange decision with regard to variable definitions, but not really a “scoping” abnormality. As in: that’s the scope you’d expect from a global variable, but not the syntax you’d expect to get you a global variable. Anyways, a base VS Code installation will throw a warning about that.

The other things are also not scoping. I’m not arguing JS is consistent, I’m just saying people should stop complaining about its scoping then offering python as a solution.

As someone who just spent a day hunting down a Heisenbug caused by using a default argument bound to a datetime.now(), I beg to differ.

Honestly, all languages have quirks. When pummeling a language for gotchas, may he whose favourite language is without quirks cast the first stone.

I don't think anyone is making a case for any given language being without quirks, but I think it's highly relevant how easy it is to stumble upon them.

If the quirks reside mostly in parts of the language only touched in really advanced expert use, it's generally not a problem because the people who venture there will know what to look out for. If your language has a quirky while statement on the other hand, it's something everyone will trip over.

E.g. Python's default mutable argument thing is fairly common to trip over (but on the other hand the behaviour is consistent and predictable once you know it), but monkey-patching builtins is not quite as common and definitely in the realm of "don't touch unless you know what you're doing".

The issue isn’t that it’s “don’t touch if you don’t know what you’re doing”, it’s “you can’t touch this at all, even if you might know what you’re doing or be willing to accept the consequences of your experimentations”

I agree with everything

May I suggest my course on the fundamentals of programming with JavaScript ES6 https://www.youtube.com/playlist?list=PL-xu4i_QDSxcoDNeh8rx5...

It is heavily inspired by SICP and covers important topics like recursion, iteration, static vs. dynamic typing, testing and more.

Each video is accompanied by a text version, a quiz and an interactive programming exercise (links are in video descriptions). The course is completely free of charge and I’ll be happy to answer any questions and help your friend solve problems if he or she decides to do the exercises on our site.

Why is JavaScript an absolute requirement? I guess he can learn python as his first programming language which I personally think will be easier to setup/run in the machine instead of installing node.

Yes. And for beginners, https://py3.codeskulptor.org/ is fantastic.

And also Python Tutor:


A great complement to that would also be to use Jupyter, whose notebooks are similarly interactive and not dead like typing into a blank terminal or IDE.

freecodecamp.org is pretty good at taking a practical approach to learning programming, primarily with JavaScript. But if your friend wants to also understand the basics of computer science it's worth considering doing both.

I guess I struggle to see why it has to be Javascript exactly (even if js6 isn't all bad). How about reasonml or clojure(script)?

Wishing for something similar in Golang!

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact