I am self taught, I worked as a lawyer for six years and four of those were spent prepping for a career change - self-teaching comp sci and software dev in the evenings, then working as a volunteer a few years in. (I come from an engineering family and should have just done it from the start, but oh well.)
I'm not sure if it's still on the platform, but about a year into my self studying I took a series of courses on edX that used this system. I think it was called Systematic Program Design, but I could be misremembering. Anyways, the courses were incredible. I completely credit them with beginning to turn me from a coder into a software dev. The system they provide just locked into my brain like it had always been there.
I almost didn't take it because it used Racket, and I questioned its general applicability for that reason. I'm so glad I pushed those concerns aside, because in addition to introducing me to software design principles, it introduced me to Lisp in a way that also completely changed my thinking about what programming itself could be.
I've now been a paid dev for 2.5 years. I don't really explicitly use the system from the course in my daily work, but the knowledge contained within it has molded my entire understanding of the field.
Once a SE discovers that they can learn, quite significantly, in a language that may have very little practical day to day use, it's a powerful moment.
Sometimes the best tools for teaching aren't the tools we need in our day to day work, and that's ok. When you're in learning mode, it's about discovering those foundational blocks upon which all else is built. Those fundamental blocks are never the actual programming language itself.
I'm sort of experiencing this myself. Currently learning C even though it's not practical in my day to day. My main language is Python and sometimes Scala. Learning about memory management, pointers, etc., has been eye opening to me (I studied math but not CS in college) and I've taken the opportunity to start digging into the CPython code base to see how Python handles things under the hood.
CPython is an excellent C code base to learn from. Readable despite being battle hardened and functional. Lisp tho is a wonder of a deeper kind - towers of dazzling beauty and power. I still recommend On Lisp by Paul Graham. And no, one won’t be using it day to day. But it will carve grooves in your brain that make you forever a deeper thinker about the possibilities of software.
I've had that moment and it's a paradigm shift in thinking. I'm still on my first leg of my journey as I started learning Racket/Scheme relatively recently but I've already started seeing things in a different light. I almost don't care about performance (at this point) as I know that could be attainable somehow once a solution is fleshed out but I simply enjoy the understanding of the concepts and the patterns that arise. At this moment I see possibilities all around and feel quite electrified.
I've not read HTDP, only very little of it. However, I find it hard to imagine, that they would not introduce data abstraction layers, like they do in SICP. So, if you relate to the usage of single linked (nested) lists, I quite sure, that improvement by switching out the data structure and putting in an appropriate one can be had. Furthermore, they'll probably teach mutation as a last resort, not as a standard thing to do, which allows for easier parallelization, provided you choose an appropriate data structure.
Once a fundamental understanding of the problem solution is achieved, one can think about refactoring steps like this. Depending on how well one wrote the code, these refactoring steps become easier or more difficult.
It's a cs101 book, they keep it simple and focus on functional programming without mutation. I was a bored business major that took the class at neu and it was a pretty amazing intro to cs that i credit for making me love cs. They got into the more advanced stuff in future courses. I love oop now, but think functional programming was a great way to introduce programming.
I see you as fortunate. I battled for years with frustration and loss of passion for coding until I ran into LISP/Scheme/Racket. I like how you put it that it "locked into my brain like it had always been there", I felt the same when I finally got to it. I also discovered this accidentally but much later in my career and only after I started lurking on HN few years ago. I am learning and toying frequently and am very excited again. To give you an example, I'm on vacation with my family and took with a me a book in logic programming in scheme which introduces the logic programming concepts, solves a few problems using the learned techniques then it goes on to to implement minikanren in less than 300 lines of code. The whole book is a mere 50 pages. The knowledge and understanding blow my mind.
Yes, this is the book and I guess I am replying to the author:) Thank you Nils M Holm. This book is very much on my taste, it contains exactly what it should and nothing more and nothing less. I guess some would prefer the Reasoned Schemer style but I find the dialogue a bit distracting for the first book.
I ordered a paperback from lulu and it was a great decision, I use a marker and write on the margins. It is absolutely worth it.
The whole series is very high grade. I don't appreciate the dialogue format all the time (too fine grained and a bit distracting after the first book). But high density of knowledge here.
It really depends on what your current situation is. Sometimes a break or distancing solves the problem. Other times it simply is trying something else, job, language, hobby. Make changes until something clicks. It sounds cliche, each person has a different journey but journeys do have some common patterns. Not sure what your frustrations stem from but I could get in touch and talk more about this.
I believe op is talking about the entire sequence where after those 2 you learn java and typescript. I also took the entire sequence the java one was really good at explaining aliasing problems, how to figure out an existing codebase by yourself, and all taught by UBC profs.
The two intro courses that use htdp are not nearly as rigorous as the book, you never get to see anything difficult enough to warrant using the design recipes where the book you begin to appreciate that style more and more as it gets harder.
The two courses of your parent comment are 2 out of 6 courses of this program [1]. It mentions Java and Typescript. It seems like all 6 can be taken for free if you click the individual links. Is this what you took?
That indeed is the course the top comment is talking about.
The instructor Gregor Kiczales has a youtube channel named 'Systematic Program Design' [2]. His 5 minutes intro video [3] is really good IMO - one can send it to ones relatives or friends who ask you what the heck you are doing in your job.
Yep well 5.5 courses I took as the last one is a big project and I already was doing one so skipped it. The java courses are good in teaching how to properly make an abstract object iirc, was many years ago I took them. Probably the best intro to programming sequence you can find though maybe not enough assignments
“Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.”
Yea, I took the course at neu and it was an amazing introduction to programming. I love oop now, but I'm pretty sure my code still has hints of this course in it. The simplicity and elegance of functional programming was awe inspiring when I took the course.
Hello, this might be a bit personal but I am a fellow lawyer having practiced law for 3 years. How did you take the plunge after six years of doing law? Were there any external circumstances? How did you get over worrying about finding a job, losing status etc.?
I dream of getting into legal tech and combine my passion for computers with my hard earned law knowledge at some point. But it's just a dream at this stage as I can see no way out.
If you can get a law degree, you can definitely learn comp sci. Lots of people with no experience think it's magic, but it really isn't that hard to learn. This book and the teachings that use it were a great way to get started when I took the course. It built a solid foundation for everything else to come when I took the course at neu.
My undergrad intro class used this. At the time I found it patronizing and silly and artificially limiting, having coded before (the design recipe, the different "levels" of scheme).
But I saw some of the wisdom in the approach when I later tutored the class. People would try to rush into coding problems without doing real analysis of what the cases would be, and had a foggy notion of different parts of program having a "contract". HTDP and the design recipe makes that muscle memory for beginners which is pretty nifty.
Matthias Felleisen was my professor at Rice 2 decades ago and I can still hear his distinctive voice clearly in my head! I too was resistant at first having done some programming in high school, but I wish I could go back and tell myself to pay attention more. Now I know Matthias was both wise and passionate and that combination doesn’t show up in every CS class, so to this day I’m nostalgic for the way he introduced computer science.
I was also a student of Prof Felleisen, and his class was both challenging and rewarding if you could stick with it.
Among other things, I learned one of my most memorable quips from him: "Don't put your ego in your code." Basically: don't consider attacks on the quality of your code as attacks on the quality of who you are. Learn, improve, and teach others the same.
Back when Felleisen was at Rice, he was the faculty sponsor for the Houston Java User Group. I attended some of those meetings, and Prof. Felleisen was mostly sitting quietly in the back of the room. Then a few years ago I ran across HtDP, and I am kicking myself for not noticing what I was missing. I should have dumped the Java meetings and sat in on his classes...
Felleisen taught the first CS class I ever took. I think part of the point of the class was to mess with people who think they know what to do because they've coded before, when in actually they are now on even footing with everyone else. In my position, I was glad for it. Everyone was perfectly intuitive!
I must be the black sheep of this thread, because I had a completely different experience. Professor Felleisen was never my professor directly, but he did oversee a few of the introductory courses I took, and was very present and had a heavy hand in many of the advanced courses. I also went to him for a number of office hour sessions.
He came off as incredibly self-absorbed and at times, borderline hostile. A sibling poster quoted him as saying "don't put your ego in your code", but in the 4+ years I dealt with him, he was nothing but ego.
I don't doubt his intelligence and obviously he's a very accomplished individual, but I just don't see what everyone else saw in him.
Back in 2008/2009, I was lucky enough to be in the NU PhD program straight out of undergrad. I had the amazing opportunity, as a TA, to teach this curriculum in the second-semester CS course that all of the CS/SE students went through.
This curriculum, along with NUs co-op model, creates some of the most spectacular engineers I've ever had the pleasure to work with. HTDP gives them the tools, and the the co-op gives them the experience. By the time they graduate, they are immediate contributors who are ready to accelerate and grow rapidly during those early years of their career.
While my undergrad experience was exceptionally different (yet equally transformative), if I could recommend a model for teaching software engineering, it would be the structure developed by the folks who created HTDP.
Speaking as a combined BS/MS grad who TA'd the first semester intro course for 6 semesters and had the pleasure of having one of the authors advise me on a senior project type thing, a big +1 to this.
I sometimes feel like I'm crazy when I tell people I wouldn't pick nearly anywhere else for undergrad CS, but time after time when I compare with peers on their experience, this model really is incredibly different and only a few others schools use it (the list is growing, but notable ones being Brown and Waterloo).
I went through the coop program at northeastern and it was amazingly pragmatic. You go to school for a career and they put a large focus on that part. They had classes like building resumes and their internship pipeline was amazing. They have tons of connections with companies and they help you with getting your foot in the door somewhere. After my first coop stint I kept working there part time through classes and I never stopped working through the end of school. I had a career and experience before I even graduated.
Also, the comp sci classes were amazing like you said. I started out as a bored business major and took the intro class that used htdp and it immediately changed the course of my life.
I'm a bit sad that contracts became the enduring legacy of HtDP and all the brilliance of the approach to recursive programming was just tossed by the wayside by the "digerati". I would have really liked to use those tools in my professional life. I guess the idea of giving up the compile step was way before its time.
Is the stack trace for a TCO recursive loop really that different from a function with a loop in it? You still see the caller and the state of the loop like recursion.
This is a book that embodies its thesis, that learning to design programs is like learning how to write or do mathematics. In the same way that academic treatments of writing or math abstract out the things you might actually do with writing or math, HTDP abstracts out the things you might actually do with a computer program. Instead you work through exercises that illustrate the fundamental concepts. I don't know that a practicing professional will learn all that much from HTDP, but it's an interesting perspective all the same.
No, I think that would be a lazy and unjustified criticism. My remarks shouldn't be taken as criticism at all. In the same way that a calculus textbook has the student work carefully constructed math problems, HTDP has the student work carefully constructed program design problems, always at exactly the right level to stimulate growth. My point is more that the setting is as different from ordinary software development as a calculus class is from the work of electrical engineering. This isn't a bad thing; just as everything I learned in calculus class helps me in my work as an engineer, everything I would have taken away from HTDP had I been taught with it as an undergraduate, would help me now. Instead, having read through most of HTDP long after my school days, I've concluded that it's a very good, systematic treatment of a subject I learned in bits and pieces along the way.
Oh wow. I love SICP. I still pick it up every now and then—just for the poetry.
The intro CS course I had taught from SICP (but the course was python, & scheme, & sql). I wasn’t so interested. I didn’t read or see the book until months after the course ended, but by then I was hooked.
I’ve never heard of HTDP, I can’t wait to read it.
When I was self-teaching, I found SICP a bit hard to really get into, luckily someone in comp.lang.lisp recommended HtDP, and I was golden, going to SICP after HtDP was a lot easier.
Kathi Fisler gave a great talk at the latest racketcon about research done based on the HtDP curriculum. I thought it was interesting to see the sorts of problems that fit well with the basic structure templates given in htdp and the kinds of problems that were a bad fit.
Another teaching language is Pyret and the book Programming and Programming Languages. It actually came out of HTDP, but uses a more Python-like syntax and explicitely uses types.
It is inspired by SICP, but in the sense that it fixes what the authors consider to be problems with SICP's approach. They've published various papers on their criticisms of SICP, eg http://www.ccs.neu.edu/scheme/pubs/jfp2004-fffk.pdf
I don’t mean to crap on something that might be great but... has anyone tried to make this usable on a phone or for even moderately poor vision? I barely noticed there was actually content to be accessed at all, just a tiny “next” black on darkish grey link.
That is always the response when people point out scribble output is unusable on many phones. But in fact people have offered fixes and they were rejected. Were they high quality fixes? I don’t know, not knowledgeable about CSS. I don’t think the project maintainers consider being useful at all on mobile a goal of scribble.
So I would say, contributions do not seem to be welcome on this topic.
It's pretty clear from this that scribble will never support mobile. I can't remember if I pulled the CSS from this change or if I came up with something myself, but making it work slightly better on my phone at least was a pretty small change, not sure if I have it around still or not.
How common is the usage of linked lists in real world Lisp projects? Isn't the prevalence of this data structure in books encourage writing inherently inefficient programs?
Hanson & Sussman have a new SICP-related book coming out which tackles similar topics: https://mitpress.mit.edu/books/software-design-flexibility This post may ultimately be downstream of people thinking about software engineering/CS textbooks and comparing.
I saw it was at least a couple of years since HtDP was discussed on HN.
I appreciate its flat footed approach and systematic method. To me, these are hallmarks of professional engineering practice. There's no attempt to make the problems more interesting by adding complexity or affectations. YMMV.
These discussions often revolve around introductory or 'first' books. What are some good followup books to HtDP, or books for an intermediate audience?
'Concepts, Techniques and Models of Computer Programming' by Peter Van Roy and Hadidi may be a better book than this and even SCP, since it presents a well organized "science" of computer programming..
I've read both SICP and CTMCP and would recommend the latter as a first read. Sure the language it teaches in is not practical, but I actually found that to take away the distractions of reading a book in whatever your target language is. Also its the first book that got me thinking about how programming languages actually work and what actually happens under the hood when you're writing code. Great book.
I also like that it is a very comprehensive book, it covers almost all fundamental approaches to programming, and clearly sets out their scopes and limitations.
Some people prefer not to commingle the functional, lambda-calculus part of a language with the parts that do side effects. It seems they believe in the separation of Church and state. --Guy Steele
A good paper describing functional programming and also talks about the differences between these two mindsets is "Conception, Evolution, and Application of Functional Programming Languages" by Paul Hudak (1989). You can find a copy at https://courses.cs.washington.edu/courses/cse583/00wi/p359-h....
I never understood the appeal of this, or SICP, or Scheme in general. I learned much more about computer science reading algorithms and data structures textbooks, especially Knuth.
There's a reason MIT uses Python for its intro courses now, after all.
SICP introduced a lot of fundamental concepts in CS to me as a junior, self-taught developer. Building everything up using immutable functions and then introducing mutable state was revelatory and still influences my design decisions 15+ years on. Scheme was somewhat beside the point.
SICP for me was the missing link between learning syntax and code to designing actual programs that solve real problems. It made me step back and look at a problem not as something that just needs a layer of code thrown at it, but as a task to complete, with requirements, constraints, etc. to consider before a single line of code is even written.
Let me say something that may reveal my ignorance, but which I'm very happy to be corrected on: for the purpose of writing moderately-sized, everyday programs, I've never needed to understand how computation works theoretically (more abstractly than introductory algorithms and data structures). And that's not because I'm not comfortable with abstraction, or because I don't know how it works theoretically, I just haven't.
Further, the obstacles I face when coding are mostly tightly coupled to the fact that I'm programming on physical hardware – again, nothing to do with the theory of computation. Even in a high-level language like Python, if you program the Sieve of Eratosthenes in a naive way without understanding what's going on under the hood with deleting an element from a list, you're going to have a bad time [0].
To caricature SICP-style instruction a bit, I'm imagining someone learning that recursion is useful (Scheme peeps seem to love it) without also being taught it generally has poor performance characteristics.
Perhaps a better criticism is the mostly useless emphasis on immutable data structures. The example I like to bring up is how Haskell for a long time didn't have a readily-available hash table implementation for completely ideological reasons. No, hash maps are strictly worse, thank you.
> To caricature SICP-style instruction a bit, I'm imagining someone learning that recursion is useful (Scheme peeps seem to love it) without also being taught it generally has poor performance characteristics.
SICP teaches that recursion can have bad performance and how to use it without blowing the stack or wasting time with unnecessary computations. Scheme, the language, requires tail call elimination so compilers will transform tail recursion into something as fast as a conventional loop.
Yes, I agree, that is a caricature. More seriously, I think leaning on this language-specific feature in a book that's supposedly teaching "general programming 101," or whatever, is in bad taste. As it says:
> One reason that the distinction between process and procedure may be confusing is that most implementations of common languages (including Ada, Pascal, and C) are designed in such a way that the interpretation of any recursive procedure consumes an amount of memory that grows with the number of procedure calls, even when the process described is, in principle, iterative. As a consequence, these languages can describe iterative processes only by resorting to special-purpose ``looping constructs'' such as do, repeat, until, for, and while. The implementation of Scheme we shall consider in chapter 5 does not share this defect. It will execute an iterative process in constant space, even if the iterative process is described by a recursive procedure. An implementation with this property is called tail-recursive. With a tail-recursive implementation, iteration can be expressed using the ordinary procedure call mechanism, so that special iteration constructs are useful only as syntactic sugar.
This is an example of a point where an algorithms book is helpful + clarifying and SICP is really not. (fake quote: "Be conceptually sloppy and let Scheme take care of it, kid.") It has a few pages on orders of growth, but the coverage is not amazing.
I wouldn’t really call tail-call elimination a feature, language-specific or otherwise. Instead, I would describe the lack of it as a bug. If you examine what’s actually going on in compilers that lack tail call elimination, what you witness is the saving of registers to the stack whose values are provably never going to be used.
Tail-call elimination / optimization is not a Scheme language-specific feature though.
Other popular languages have TCO to varying degrees, like C and C++ when using fairly standard compilers like MSVC, GCC, Clang, or ICC [1]. Destructors do get in the way though sometimes.
Java/JVM doesn't support TCO, but Kotlin and Clojure make do with special syntax to support tail-recursion (i.e. tailrec, recur).
Apparently JavaScriptCore supports TCO for JavaScript [2].
The book makes it sound like TCE is language-specific, but since that book was published, it's spread to many other mainstream languages too.
I don't think that's the point, as conversion in both directions is near trivial. It is a straightforward mechanical process, it may not always be easy or simple but it's more likely tedious than hard or complex.
More importantly, in the listed languages (excepting a handful of compiler optimization options) the semantics of procedure calls are different than Scheme's semantics for procedure calls. So if you, in C, convert a for loop into a tail recursive procedure you have changed the behavior of the program, not just its appearance (and same in reverse). In Scheme or another language with tail call elimination, then this conversion ought not actually change the behavior of your program (done in either direction). This also has the effect of removing the loop constructs as a necessity of the language. You can describe an efficient iterative process in Scheme with tail recursion, but you cannot describe it (in a general sense, same caveat for some optimization options) with tail recursion in the listed procedural languages and must use a special syntax element (their loop constructs) to achieve the same program semantics.
Transforming a program with tail calls to one without require to move all mutually recursive tail function to a common trampoline or something similar. Rewriting a single or a few tail functions into a loop/switch is easy, but it "impossible" to do for library API without global transformations.
(I could be wrong, I am not an expert in this, my basis are that an open set of function with a call in tail position can be used to describe arbitrary state machines (with the state being the arguments of the tail call and the rules the code of each function) that is open to new functions being added from anywhere. If you want to transform this in an iterative state machine all your functions need to be "registered" and "called" by the state machine.)
> Perhaps a better criticism is the mostly useless emphasis on immutable data structures. The example I like to bring up is how Haskell for a long time didn't have a readily-available hash table implementation for completely ideological reasons.
Can you link to some evidence that the reasons were completely ideological?
From Knuth’s The Art of Computer Programming. MIX is the earlier version, MMIX is the more recent (though now 20 or so years old) version. They are descriptions of a computer architecture and machine instructions used to explore algorithms in his books.
Knuth's TAOCP was originally written in an imaginary 60s-style CISC assembly called MIX (with some oddities like being decimal) but newer editions are in a RISC style one called MMIX (which Knuth claims is more practical but really isn't.)
Well, all I can say about that is that I read through the MMIX supplement and did a bunch of the exercises, and I know have enough knowledge to vaguely understand assembly.
It hasn't been massively useful to me in my professional life (I'm a data scientist), but it definitely has helped me to gain a deeper appreciation of how computing works.
> There's a reason MIT uses Python for its intro courses now, after all.
Yes, and IIRC, that reasons were, roughly: a) Python is more popular, b) Python has better robotics libraries, which is what kids coming to MIT care about these days. Notably, I don't recall the reasons they given having anything to do with giving students a good fundamental understanding.
But this is exactly my point. I think it's essentially a myth that Scheme/SICP are somehow more well-suited to providing a "good fundamental understanding." And Python is, as you point out, more practical and accessible.
While I have friends (and many colleagues) who graduated from MIT CS and are very competent engineers, I don't think MIT is the shining beacon of the best SE/CS graduates. Their program is certainly very good, but if someone asked me (for CS/SE specifically) about going to MIT or NU, I'd point them to NU. For almost everything else, it would, of course, be MIT.
Ah, thank you. I was thinking of Northwestern. To the point of comment you replied too. I do believe there is value in what can be more understood between learning via HTDP vs an easy to understand language, Data Structures, and Algorithms. From stand point of teaching CS to beginners maybe MIT is going for breath and Northeastern is going more for depth.
Then again what do I know, I didn’t go to university remotely in that realm of prestige.
I'm not sure if it's still on the platform, but about a year into my self studying I took a series of courses on edX that used this system. I think it was called Systematic Program Design, but I could be misremembering. Anyways, the courses were incredible. I completely credit them with beginning to turn me from a coder into a software dev. The system they provide just locked into my brain like it had always been there.
I almost didn't take it because it used Racket, and I questioned its general applicability for that reason. I'm so glad I pushed those concerns aside, because in addition to introducing me to software design principles, it introduced me to Lisp in a way that also completely changed my thinking about what programming itself could be.
I've now been a paid dev for 2.5 years. I don't really explicitly use the system from the course in my daily work, but the knowledge contained within it has molded my entire understanding of the field.
The course literally changed my life.