4 ms·
SICP was ported to JS though I'm not particularly keen on the result. https://sourceacademy.org/sicpjs/ https://sourceacademy.org/sicpjs/ The code is convolute
by Jtsummers 2y ago
SICP was ported to JS though I'm not particularly keen on the result. https://sourceacademy.org/sicpjs/ https://sourceacademy.org/sicpjs/
The code is convoluted, in my opinion, because it tries to hue too closely to the Scheme code in the original giving some unnatural looking JS code as a result. For example:
function member(item, x) {
return is_null(x)
? null
: item === head(x)
? x
: member(item, tail(x));
}
There are examples which have even more but that was the first one I came across clicking the TOC randomly. In Scheme it would be expressed something like this:
(define (member? item set)
(cond ((null? set) #f)
((equal? item (car set)) #t)
(else (member item (cdr set)))))
While the parens cause some brains to segfault, the structure of this (how each condition ties to each result) is clearer than that JS mess.
- shawn_w 2y agoI'm convinced someone wrote a (bad) Scheme to JavaScript transpiler to convert the code. It looks like nothing anyone would actually write.
- nvlled 2y agoI've seen code like that in production, it's not as strange as you think (pretty common in reactjs codebase). After a while, you just get used to it and read past the weird syntax. It's not really that different from a switch-case or if-else block: function member(item, x) { return /* if */ is_null(x) ? /* then */ null : /* elif */ item === head(x) ? /* then */ x : /* else */ member(item, tail(x)); }
- xiaoyu2006 2y agoIt’s not the language to blame in SICP, if any. Scheme is totally find (and cool).
- neilv 2y agoExtra whitespace to put the `cond` clauses in columns can make it even more clear, for "visual" looking at code, rather than only "verbal": (define (member? item set) (cond ((null? set) #f) ((equal? item (car set)) #t) (else (member? item (cdr set))))) For bonus points, line up the key variable in the clauses, and it's easier to see visually that the `cond` is about that one variable: (define (member? item set) (cond ((null? set) #f) ((equal? (car set) item) #t) (else (member? item (cdr set))))) Which accidentally also lines up with one of the procedure's arguments, though I didn't intend that one, but you could double down on that: (define (member? item set) (cond ((null? set) #f) ((equal? item (car set)) #t) (else (member? item (cdr set))))) This isn't some deep thing; just a little example of how sometimes whitespace, other than just indenting at the beginning of the line, helps to exposure some of the structure visually.
- z3t4 2y agoIn my humble opinion, a for loop is easier to reason about then recursion. So one of JavaScript's "features" is that it does not have proper recursion support, so you need to break out the recursion into a for loop, or the call stack will eventually become too big.
- williamdclt 2y agoWhat do you call "proper recursion support"? I assume it's tail-call optimisation, but I don't think it's a property of Javascript-the-language, but rather a property of the interpreter/compiler? I don't think there's anything inherent to javascript that would prevent V8 to have TCO (and I think it did use to have it) for example. And in fact I _think_ some engines do have TCO (bun? javascriptcore?), but I could be wrong
- Jtsummers 2y agoES6 added this: https://262.ecma-international.org/6.0/#sec-tail-position-calls https://262.ecma-international.org/6.0/#sec-tail-position-ca... So TCO is part of the language standard but not universally implemented. You are correct about the ones that support it.
- soegaard 2y agoThe authors of the JS version of SICP had a problem: Scheme is expression based and JavaScript is statement based. When I say Scheme is expression based, I am alluding to the fact that constructs such as `if`, `cond`, `case` etc. are all expressions. Scheme also has several binding constructs (let, letrec, etc) that allows in an expression context to bind the result of a computation in a subexpression. These are all expressions. The expression version of `if` is in JavaScript called ternary if. A direct translation from Scheme to JavaScript therefore uses ternary if. But why make a direct translation? Well, later in the book one writes an interpreter for Scheme. This interpreter shows how the expression based language constructs are implemented. It is therefore necessary that the reader is very familiar with these constructs.