Let’s look at how JScreme compiles a few simple examples:

Scheme JavaScript 123 123 #\a "a" "abc" "abc" #t / #f true / false

Functions are also easy:

Scheme JavaScript (lambda (x) x) function (x) { return x; } (f x) (f (x)) (apply f x y z) (f.apply (null, [x, y].concat (list_to_vector (z))))

The only rule here that merits explanation is the one for apply . In case you’re not familiar with Scheme’s (or most other Lisp’s) apply , here’s an equivalence:

apply no apply (apply f 1 2 '(3 4)) (f 1 2 3 4)

So, apply takes a function, some arguments, and a list of more arguments, and calls the function with those arguments. The reason apply is needed is because it lets you call a function with a number of arguments that is not statically known.

The function list_to_vector above converts a Scheme list into a vector, i.e. a JavaScript array. It’s implemented in Scheme as well. We’ll get to the details later.

Obviously there must also be a way for a function to receive a variable number of arguments:

Scheme JavaScript (lambda (x . y) y) function (x) { var y = listify_vector (arguments, 1); return y; }

Here, the function listify_vector converts the arguments array, starting at index 1 , into a Scheme list.

At this point I should mention that I’ve been lying a bit about names. Due to JavaScript’s scoping rules being slightly different than Scheme’s we must make sure that different variables have different names in JavaScript, even though they’re named the same in Scheme. The easiest way to achieve that is to use a name generator to create a unique name for each variable. In Lisps, it’s usually called gensym . So, this is what code actually looks like:

Scheme JavaScript (lambda (x) x) function(__space_g8757_){return __space_g8757_;}

Of course there’s also if :

Scheme JavaScript (if a b c) (a ? b : c)

For simplicity’s sake JScreme also implements letrec in the compiler. It creates a new function to make scoping easier and to be able to treat the whole thing as an expression: