Obvious objections - JS has no tail call elimination, no macros, and state-changing is managed with entirely different conventions in Scheme. Also the conceit of SICP (not really justified) is that they don't have to teach you syntax, because homoiconicity. Still, I think it's a worthy pursuit to try to bring the insights of this book to a wider audience.
Side note: the navigation is really irritating. The back button only works sometimes, because it's replacing content without doing some kind of pushState. So you have to hunt for links.
Another side note: Sean Burke and Piers Cawley have ported some of mjd's excellent book Higher-Order Perl to JavaScript. This might be even better, because both Perl and JS have C-like syntax hiding some impressive functional capabilities. I wish someone would finish that, but I guess few people even know about HOP, these days.
It depresses me how much of HOP is irrelevant in Python because they have proper iterators. And how few Perl programmers realize that these days the lack is a major omission in the language.
I'm a longtime perl user, and I don't know where my blind spots are.
Are there any particular resources you would recommend for someone like me to get going quickly with python? In particular ones that specifically address the type of blind spot you mention?
The iterator section is http://docs.python.org/2/tutorial/classes.html#iterators. Here it is quickly. Suppose that an object has a __iter__ method which will return something with a next method that will, when it has exhausted the iterator, call StopIteration. Then all native looping constructs can loop over that object and it will just work.
If you call a function that internally calls yield and nowhere calls return, then you get back a generator, which is an object with those methods.
There is also syntax to construct such generators inline without even an explicit function.
All of the closure based looping stuff in HOP which supports potentially infinite streams? It is all built in!
Not really. As ~btilly suggested in another post, perl really doesn't have anything like it. The closest thing that exists is using a code reference.
sub new_iter {
my $i = 0;
return sub {$i++}
}
my $iter = new_iter();
while(my $number = $iter->()) {
say $number;
}
This is of course a trivial example, but it does give a bit of an idea of the only way Perl has to be able to implement them, essentially anonymous functions and closures. This is useful, but it doesn't make it easy to take say a red-black tree, and iterate over the entire set of values in it (though with higher level languages like perl, you probably wouldn't implement much with a red-black tree, maybe a k-tree would be better?)
"Sweet.js brings the hygienic macros of languages like Scheme and Rust to JavaScript. Macros allow you to sweeten the syntax of JavaScript and craft the language you’ve always wanted."
It might be worth noting that this class (CS1101S in NUS) stops at chapter 3 of SICP. I took the previous scheme version of the class.
Btw, I'm curious as to why the HOJ book didn't get taken down? I checked and the HOP book is not released under a license that allows for derivative works. I'm curious because I've made an interactive version of SICP (using scheme) and I can't find any other books to do this to because no one releases books under permissive enough licenses.
Drivers maybe not, but after reading coreutils/ls source code, I think most of the userland part of my OS would probably benefit from a rewrite in js/v8.
In terms of the aesthetic pleasure you derive from reading the source, or the functionality of the artifact? I mean, saying everything but drivers would be better in js/v8 sounds absurd to me. You think the Linux kernel would be better performant written in js/v8? Your GDE? Window manager? Package manager?
I was careful in picking my words. I don't think Javascript is suited to express kernel level system control. There are many windows managers written in dynamic languages (lua, python, lisp). GDE = Desktop Environment ?
I don't know if computing Package Manager dependency graphs be that slower if written in js, probably.
Beside the point was not about micro benchmark performance but about separation of concerns and reuse, more than a third of ls is output formatting.
I just want to meet one programmer who can work on server side code, client side code, etc who can't handle them being written in different languages. This fad just doesn't make any sense to me. Let's reinvent the wheel so we can have JSON literals instead of Ruby hashes!
I always thought this would be self-evident to people, but apparently not: The reason why I want to have Javascript on both the client and the server is so I can re-use code.
My software has a fairly large chunk of code which is a gardening expert system. I'm hesitant to call it AI because it's so dumb, but it's along those lines. It knows things like "If you live in Phoenix and it's April, you should wait to plant your lettuce until September".
It's useful to have it on the client, when you're in the garden and there's no connectivity, or when you tweak your settings and don't want to have to download a bunch of "conclusions" from the server. It's useful to have it on the server so that the server can send emails, pre-cache HTML for faster loading pages, etc.
If my server is written in Ruby (which is is right now) then I have to re-implement that entire system twice. That's double the code. It feels gross. And I can't help but feel like most web-apps have code like this that could be shared between the client and the server.
Fortunately, I think we're entering an era where JS can be a nearly transparent target language for translation from the languages of our choice, with things like asm.js and source maps. We're not quite there yet, but it definitely seems like where we're going.
I'd prefer the other way round. JavaScript is better than most popular programming languages (including Python). It is not perfect, so I consent there might better languages out there.
Sounds like that part of the system could be written once (in any language) and then encapsulated and treated as a local service... (analogous to using a local copy of SQLite if you need a db). Then you can use the "best tool for the job" on the client and-or server?
Then so be it. "The best tool" is a complex multi-value optimization that includes intangibles like personal preference. For me personally, server-side js wouldn't make any sense (right now) -- it's not my preferred language and it doesn't have the same sort of library support as other langs.
Yeah, I'm with you on this. Aesthetically, I'm in the "ugh, Javascript" camp. But practically, I recognize that I should just get over this. For web stuff, I fully expect that I'll be writing everything in JS in a few years.
Considering it doesn't even support multiple core processors, and processors are only coming out with more and more cores, I doubt it. This is assuming you are actually doing something that requires performance. Check out Elixir or Go if you want something new that actually makes technical sense.
Sorry, by "web stuff" I meant the client side plus the first tier of stuff. I agree that for serious computation I want something else. Thanks for the tip on Elixir, though; that looks appealing.
If the language can do so competently, why not? I think that would be a great leap forward for programming as it would consolidate efforts developing libraries, documentation, and tools.
As others have pointed out, chapters 4 and 5 are as wonderful and rich as they are because Scheme is homoiconic which makes writing Scheme interpreters and compilers in Scheme very easy -- no need for hairy lexing and parsing steps. Since (IMHO) these chapters are the best introduction to the study of programming languages and their implementation, it would be a real shame to discard them simply because JavaScript is more widely known and used than Scheme.
It's true that the ideas in the book transcend programming languages, and that the first 3 chapters could probably could be covered in JavaScript with little modification, if a little clumsily. But rewriting the 4th and 5th to include sections on parsing JavaScript would be quite challenging, and furthermore JavaScript does not have as simple semantics as Scheme, so there would be a loss of a great deal of elegance and beauty. The metacircular Scheme interpreter can run itself, which would be harder to do in JavaScript since its core is more rich and Scheme's core: objects, methods and so on complicate it quite a bit.
By the way, I read SICP and it's one of my favorite book. It's unbelievable how quick things are hacked... i.e. 2 pages and you've got a SQL-like language. Also, I must agree that Scheme really fit with the theme and the book. It's clean, it's concise, there's no funky syntax to learn. And, I also must agree that the interpreter and compiler parts would be much much more complex in JS.
All that being said, I still think lots of great concepts behind SICP can be explained with JS as the main language instead of scheme. If it can help some people to feel at home and quick the book, that's just great. They'll most likely like it and then read the real SICP for the other parts.
Lastly, I must agree that when I read SICP the first time, it was also to learn scheme as a side-effect. But it's not necessarily everyone.
and that metacircular evaluator is probably my favorite part of the (original) book right now...
"It's as if -- as if the key to the treasure is the treasure!"
i think the (new) book is valuable in that it might reach some people who have some mental block about just wanting to know what they "need" to know and think that all they need to know is javascript, but for those who just like learning? start scheming. it's freakin' awesome.
Really sad to see that such amazing book that uses such nice language is now transformed to monster with JS. Why would you do that? Painful to see all that...
Most of chapter 4 will be impossible to really translate to JS because JS has no macros (required to implement some of the special forms like delay) and isn't homoiconic.
It's not about macros, it's about homoiconicity. I encourage you to read chapters 4 and 5 and think about how sweet.js would help you port those chapters to JS.
The world is not entirely composed of consumer web startups. There are plenty of opportunities that don't share the tradeoffs inherent in the typical HN style environment.
For anything else, there are endless languages to choose from.
The Americans have taken over and the Americans have, based on their own linguistic experience, decided most people can only handle one spoken language and one programming language.
For some of us, we can handle six programming languages and be fine.
For "average" people, they're lucky to get one programming language, so it was decided to fad-hype-hipster promote One Language To Rule Them All for fronted, backend, sideend, middleware, topware, bottomware, programming your embedded system, programming your car, scripting your operating system, and programming your blender.
Look on github for how many people write shell scripts in ruby because they don't know how bash works. You can find the same over-syntax'd-programming-environment-as-shell-script with node too. We're the exceptions. They can't handle the truth.
> Look on github for how many people write shell scripts in ruby because they don't know how bash works. You can find the same over-syntax'd-programming-environment-as-shell-script with node too. We're the exceptions. They can't handle the truth.
As someone who has done this (and who currently works in C), I will say only that shell scripts translated to Ruby can be a lot easier to read and maintain than those written in bash... if I get to the point where I'm having to pipe to more than two of awk/sed/grep I will generally just write it in Ruby, because then my mother could read it. YMMV though. In every other sense I agree with you entirely, and I think the proliferation of JS rewrites of things that work in actually-designed languages is appalling.
You found the one exception. There's a fuzzy line when dealing with shell scripts.
If you're just iterating over a directory and checking some files, that's great shell script territory. If you're making a launcher script for another program to set the environment, check directories, fix permissions, and run pre-flight checks, that's great for shell script.
But, sometimes we end up with feature creep. You start out with "Well, this shell script just has to parse some CSV and insert into sqlite" then before you know it, it also has to check another pre-existing DB for redundancy checks or constraints, then you're 100 pages into the Advanced Bash-Scripting Guide trying to make Bash do something that would be a six liner in Perl 4.
The benefits of over-programming bash scripts is extensive portability though (if you make sure you aren't using features only in very late version of the shell).
> If you're just iterating over a directory and checking some files
Unfortunately, I very frequently see this in shell scripts...
ls $SOME_PATH | awk...
I even once saw someone use ls to figure out if a certain file was a symlink by looking for "->"! That kind of stuff doesn't typically happen in other languages.
Most programmers never heard of Fizzbuzz, the point of it is merely to screen out candidates who can't come up with their own solutions to problems.
A lot of so-called experts aren't capable of doing more than copy other people's solutions. Fizzbuzz offers a simple but new problem for candidates to solve.
Scala for the win. Most of the ruby goodness with non of the performance problems (at high scale (ie Twitter ...), because ruby is fine for most use cases ).
Go is fine, but i dont like the syntax and some of the language design choices
Background: this is the textbook used for a class at NUS (National University of Singapore). Previous iterations of the class, CS1101S, used the original scheme version of SICP, but omitted chapters 4 and 5 in the interest of time. [1]
I took the scheme version of the class and learned a ton. From what I've heard, the reasons for the switch included javascript being more practical and the previous professor deciding to take a break from teaching that class. Basically, many of the reasons overlap with that for Berkeley switching 61A from scheme to python [2].
I've also heard that the javascript version of the class is just as rigorous and challenging as the scheme version.
Due to the increasing popularity of casual dining and the decreasing accessibility of Danish nobility, I've rewritten Hamlet to be an Appleby's assistant manager.
The fifth act of SICP is meta-linguistic abstraction, and among Javascript's merits it is not. SICP is no more a book about Scheme than Moby Dick is a whale tale.
I admire the effort, and understand the sentiment behind the project. I just think the authors are missing the big picture of SICP. In fairness, few of us are Ablesons or Sussmans.
> Due to the increasing popularity of casual dining and the decreasing accessibility of Danish nobility, I've rewritten Hamlet to be an Appleby's assistant manager.
Replace "casual dining" with "megacorporations" and you get an actual movie made in 2000 [1]. And, of course, that example is not unique [2][3][4][5][6][7][8][9][10].
Scheme is a deliberately minimalist language, which is fairly accessible and easy to write your own implementation of. In fact, in SICP, you do that, a couple of times, writing first a Scheme interpreter, then extending it in various ways like adding logic programming capabilities, then you write a virtual machine and a compiler that compiles down to that virtual machine.
JavaScript is, well, a weird and warty language. You wouldn't want to try implementing JavaScript in an introductory CS class, and it's much less amenable to language extension like the logic programming variant of Scheme you implement in SICP.
But I notice that this translation of SICP into JavaScript doesn't got that far; it only goes up through Chapter 2 of SICP.
I'm not a big fan of R6RS, but it is still fairly minimalist. One of the good things that it did was divide the standard into a core language, and standard library built on top of the small core language. The core language eliminated many things from R5RS, but the standard library adds a lot more.
The main issues I have with R6RS are the library system (which I think is too complex, and it frustratingly adds an extra level of indentation as you need to wrap everything in one big expression), and some of the libraries in the standard library, like the I/O library, the Unicode library (which standardizes on such things as char-upcase and char-downcase, which are fairly useless in a Unicode context, without adding much that's actually useful).
R6RS is this kind of weird, awkward beast that's not sure what it's doing. It neither strips the language down to a minimal core, nor does it build up a comprehensive set of libraries containing all of the basics that people expect from standard libraries in a language these days.
Actually, Scheme is more accessible than ever before. If installing MIT Scheme and Edwin/Emacs is too difficult, now there's Racket-SICP, which allows you to program with DrRacket, a beginner-friendly graphical IDE, and actually comes with implementations of some parts of SICP that MIT Scheme omitted, like the picture language and (afaik) some concurrency primitives.
Is Scheme really decreasing in usage? Sure, in recent years there have been high-profile moves to Python at MIT and UCB, but I don't know of any hard stats on worldwide Scheme usage. Not that it matters.
SICP isn't a book about Scheme. It's a book about writing computer programs. Scheme was used because it imposes the minimum additional cognitive load. Worrying about all the warts in, e.g. Common Lisp (to say nothing about Javascript or Scala, say) would detract from the pedagogical mission of the book.
No "click through Visual Studio's project setup" phase, no "how do I open the text editor from IDLE" phase, no "open a command prompt" it's all right there.
This makes the environment and the language perfect for beginner students.
Meta-gripe: the navigation seems to use some kind of asynch loading without pushing to the browser history stack, and I'm finding it very difficult to move back and forth from the ToC to chapters. Maybe this can be addressed.
JonesForth at least seems in the same spirit as SICP, though what it accomplishes is different.
It explains and implements a Forth environment from scratch, initially in literate assembler code (yes, that exists) and then, once that's bootstrapped enough, in literate Forth that it runs using itself.
Side note: the navigation is really irritating. The back button only works sometimes, because it's replacing content without doing some kind of pushState. So you have to hunt for links.
Another side note: Sean Burke and Piers Cawley have ported some of mjd's excellent book Higher-Order Perl to JavaScript. This might be even better, because both Perl and JS have C-like syntax hiding some impressive functional capabilities. I wish someone would finish that, but I guess few people even know about HOP, these days.
http://interglacial.com/hoj/hoj.html
http://www.bofh.org.uk/2010/11/18/higher-order-javascript