Scheme of some sort ideally - either MIT Scheme or Racket will do nicely. I seem to recall that someone was working on a version of SICP with examples in Clojure, but it may be incomplete.
> Quite a bit of SICP would be awkward to translate into a language that doesn't support TCO, such as Clojure.
Clojure doesn't have implicit tail call but it does have loop-recur and trampoline. SICP can be followed quite easily in Clojure.
It can very well be followed in Ruby or Javascript as well. No tail calls simply means the runtime won't be iterative. TCO are a very small aspect of what SICP teaches, and I don't see why absence of tail calls should stop anyone from following the book in their language of choice(at least the first 3 chapters).
> It can very well be followed in Ruby or Javascript as well.
Regardless of TCO issues, I don't think this is a good idea, since you'd miss out on the real treasure of chapters 4 and 5, where using a Lisp lets the authors demonstrate interpreters and compilers without mucking around with parsing.
You've obviously read it, so this is just advice for anyone considering reading it using some other language: Just use Scheme, the flavor that SICP uses is a tiny subset and it takes a single lecture from the videos for them to explain it.
> since you'd miss out on the real treasure of chapters 4 and 5,
> so this is just advice for anyone considering reading it using some other language: Just use Scheme, the flavor that SICP uses is a tiny subset and it takes a single lecture from the videos for them to explain it.
I would say for anyone on the fence, use Ruby, JS... if you don't know scheme and aren't willing to learn it to read a book. By the time you will reach 4th chapter, you will already know enough scheme. The book doesn't assume prior knowledge, and since you are translating scheme snippets, you already are practicing scheme.
I am not saying scheme is not the ideal language for the book; it is. I am just saying you can dip in your toes with the language of your choice.
This section relies on TCO. I realize that it could be translated, but I do not feel that this could be done without heavy modification. Besides that, basically the section's goal is to explain TCO.
> Quite a bit of SICP would be awkward to translate into a language that doesn't support TCO, such as Clojure.
>> Clojure doesn't have implicit tail call but it does have loop-recur and trampoline. SICP can be followed quite easily in Clojure.
>>> http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html....
This section relies on TCO. I realize that it could be translated, but I do not feel that this could be done without heavy modification. Besides that, basically the section's goal is to explain TCO.
Ah, I stand corrected. The last time I used Clojure (a few years ago), recur needed to be used with loop. That looks plenty close enough to the Scheme.
I disagree that the Ruby example is sufficient, though. Remember, SICP is intended as an introduction to programming. A chapter like this is useful to people who do /not/ understand TCO, recursion, and the stack already. Understanding it and using that knowledge to translate the exercises is different than having a shaky grasp lisp, scheme, and the "interpretation of computer programs"
TCO refers to tail call optimization, which is a useful optimization for languages such as Scheme which encourage heavy use of recursion. TCO allows the interpreter to reuse the current stack frame when a tail-recursive[1] function calls itself instead of creating a new stack frame for each recursive call.
Because javascript lacks this and many other features of Scheme/Lisp, I wouldn't really recommend using it for SICP.
[1] Tail recursive functions are recursive functions which merely return the result of their recursive call to the caller instead of further processing those results before returning. In pseudocode:
// non-tail
expt(b, x):
if x == 0: 1
else: x * expt(b, x-1)
// tail-recursive
tail-expt(b, x, ans):
if x == 0: ans
else: tail-expt(b, x-1, x*ans)
TCO is an optimization, it doesn't affect correctness. So you can ignore not having it, until you run out of stack.
There is a much bigger reason to stick with Scheme for SICP: all the meta-circular evaluator stuff where you learn to implement Scheme in Scheme. I supposed you could implement Scheme in Javascript, but then you'd still need to learn Scheme. And you certainly won't want to implement Javascript in Javascript.
>TCO is an optimization, it doesn't affect correctness. So you can ignore not having it, until you run out of stack.
Correct. Though CPU performance is an issue that tail recursion optimisation addresses too. For simple functions building up the stack frames and deallocating them afterwards can be more work than the function itself. For deep recursion stack space is the problem you usually hit first, but for code with tight performance requirements no always.
>And you certainly won't want to implement Javascript in Javascript.
Oh I don't know, it could be an interesting project if only for an exercise in intellectual onanism!
In fact I've heard of it being done a few times. The first ones that pop up in Google are http://sns.cs.princeton.edu/2012/04/javascript-in-javascript... which is aimed at sand-boxing (and looks like an interesting if not efficient idea) and https://github.com/mozilla/narcissus/ which has the stated goal of being used for experimentation with the language itself (so the fact it is implemented in javascript is probably less relevant).
> Because javascript lacks this and many other features of Scheme/Lisp, I wouldn't really recommend using it for SICP.
A language without TCO won't affect what you get out of SICP. Just assume JS is tail recursive. The first 3 chapters can be done(with some translation) in JS.
Glad I could help. Scheme is great for introducing oneself to many concepts not commonly present or used in more common imperative languages. That, and the SICP is just a ton of fun.
http://racket-lang.org/