Hacker News new | past | comments | ask | show | jobs | submit login
SICP translated to JavaScript (nus.edu.sg)
154 points by Splendor on Sept 14, 2013 | hide | past | favorite | 107 comments



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.

http://interglacial.com/hoj/hoj.html

http://www.bofh.org.uk/2010/11/18/higher-order-javascript


I know HOP.

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 Python tutorial teaches the language fairly well: http://docs.python.org/2/tutorial/

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!


s/call StopIteration/raise StopIteration/g


I wrote a tutorial a while ago exactly for this purpose:

http://www.stavros.io/tutorials/python/


JavaScript doesn't have them either, until you include a functional toolchain library like Underscore. Does Perl have any similar library?


JS 1.7, already available in some browsers and bleeding edge Node, has iterators and generators.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...



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?)


There are plenty of iterator/generator libraries on CPAN. My personal favourite is Coro::Generator - https://metacpan.org/module/Coro::Generator

Re: Underscore... there is a Perl port - http://vti.github.io/underscore-perl/


Macros in js: http://sweetjs.org/

"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."


> Use the sjs binary to compile your sweet.js code:

That isn't JavaScript.


It's not in the core language but it fits in well with the JS ecosystem, and could be used for the purposes discussed here.


>JS has no tail call elimination

Apparently this is changing with ES6.


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.


tail call elimination can be implemented in javascript: http://raganwald.com/2013/03/28/trampolines-in-javascript.ht...


Trampolines are a solution to the same problem that tail-call elimination solves; they're not transparent to the programmer.


> Also the conceit of SICP (not really justified) is that they don't have to teach you syntax, because homoiconicity.

What syntax is there to teach?


What's next? "Advanced Programming in the Unix Environment: Now with Javascript!" ?

Or "Linux Device Drivers: Javascript edition" ?

Can we just accept that JS is not for everything?


But I'm an intellectually lazy techno-hipster who doesn't want to learn new programming languages!!


Atwood's Law "any application that can be written in JavaScript, will eventually be written in JavaScript."

http://www.codinghorror.com/blog/2007/07/the-principle-of-le...


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?


> most of the userland part of my OS

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?


What if JS is the best tool for the job?


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.


Or Clojure, which has a good concurrency story as well as compiles to javascript.


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.


Maybe not everything, but to explain the concepts behind SICP, why not.


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.


Not to mention that if you are already learning the concepts taught in SICP, then learning Scheme is trivial.


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...


This will only serve to perpetuate the stupid meme that "Javascript is basically Scheme with curly braces and semicolons"


http://journal.stuffwithstuff.com/2013/07/18/javascript-isnt...

(Note that the author intended this to be humourous/exaggerated - Some people took exception though.)



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.


Okay, that's cool, but I still think a lot of the explanations wouldn't make sense with code translated to JS, because of the lack of homoiconicity.


Can it use JS for transformation logic?


Some people will stop at nothing to convert the world to JavaScript and Ruby.

(please don't do the latter... or is it too late?)


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.


The web developers have taken over, it seems.

Edit: I say this as a web developer. I feel like it's often forgotten that Ruby and Javascript aren't the only languages worth using.


Well, I never used Ruby, besides to see what this Ruby on Rails was all about and I already knew Python since the version 1 days.

For me the only place for JavaScript is on the browser.

For anything else, there are endless languages to choose from.


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.


Except if by portability you include non-unix systems. Then you're probably better off with Perl (for example) again.


Very well said.

> Look on github for how many people write shell scripts in ruby because they don't know how bash works.

I have seen this happen in a company I used to work for, when new system engineers came on board, but in this case it was Groovy.


>> lucky to get one programming language

to get? I'm not sure what that means.


get, grock, understand, comprehend, become one with

"I don't get why people live on geologically mapped flood plains."


Ah damn. My bad. Seeing this in Javascript has sort of disoriented me.


@seiji

Average programmers aren't working on shell scripts, client side code, and server side code at the same time.


And everyone is better than the average. :)

Honestly, HN too has hordes of people who can't write FizzBuzz. No reason to feel elitist for anybody really.


FizzBuzz seems to be an American thing.

I have been coding since 1986 and only learned about it via the usual HN hiring discussions.


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.


Are you sure about that? Everyone on my team does. I can't really imagine not being able to build the full stack.


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


Porting it to javascript kinda defeats the idea that principles described here transcends any current trend.


BINGO!


What an abomination.


Wow, stay classy.


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.

Shameless plug: if you want an interactive version of SICP in the original scheme, check out http://xuanji.appspot.com/isicp/1-1-elements.html

[1] Which might explain why the lack of macros in javascript wasn't a concern

[2] http://www.eecs.berkeley.edu/~bh/61a.html


why, God, why?


>>why, God, why?

I really loved that response :)


Perhaps due to the increasing popularity of JavaScript and the decreasing accessibility or usage of Scheme.


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].

[1] http://www.imdb.com/title/tt0171359/

[2] http://www.imdb.com/title/tt0114279/

[3] http://www.imdb.com/title/tt0117509/

[4] http://www.imdb.com/title/tt0184791/

[5] http://www.imdb.com/title/tt0265713/

[6] et cetera

[7] et cetera

[8] et cetera

[9] ad nauseum

[10] ad infinitum


Thank you for the imagery. As Dane who grew up in Elsinore, it will stay with me for quite a while I am sure.


SICP uses Scheme, not Common Lisp.

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.


JavaScript is rather minimalist as well. It has some warts, but they are easy to avoid.


> Scheme is a deliberately minimalist language

Ever looked at R6RS?


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.


SICP did not use Scheme. SICP used a tiny subset of an early Scheme.

You can use a subset of Common Lisp and the programs in SICP would mostly look the same when written in that CL subset.

I have a surprise for you: Scheme has warts, too.


> decreasing accessibility

Scheme is super-easy to set up these days.

Step 1: Download http://racket-lang.org/

Step 2: Follow the quick start guide: http://docs.racket-lang.org/quick/

Step 3: Click "Run"

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.


SICP uses Scheme, not Common Lisp.

Edit: Here's a list of available Scheme implementations. SICP uses MIT/GNU Scheme, which uses an Emacs-like editor.

http://groups.csail.mit.edu/mac/projects/scheme/


Thanks, you're correct.


Now if someone would only translate it to Visual Basic it would be truly accessible.


Preferably classic Visual Basic, not the .NET edition :-)


VB6 had the best write code at run-time debugger I've ever seen, it's too bad the language itself was so lacking.


VB 6 doesn't have lambdas, VB.NET does have lambdas.


Plenty of Scheme implementations work in JavaScript VMs.


Cool - next they should try "How to Solve it by computer" (http://www.amazon.com/Computer-Prentice-Hall-International-S...)


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.


Check out my new library, SICPinJSnavigation.js


Why so square? Translating SICP to Forth would be at least eclectic and truly creative gesture.


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.

http://sage.math.washington.edu/home/wstein/www/home/wbhart/...


"An invasion of armies can be resisted; an invasion of ideas cannot be resisted" - http://en.wikiversity.org/wiki/Victor_Hugo_quote

This generation is going to be rewrite in Javascript/v8, everything that can be written in Javascript.


And a few things that can't, I suspect.


Btw Prof. Martin Henz was one of the major contributors to the design of Oz.


It's like you didn't even understand why it was done in scheme...


Wanted to care but the page wouldn't display without Javascript.


blasphemy!




Consider applying for YC's W25 batch! Applications are open till Nov 12.

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

Search: