Second Class Citizens
![]() |
| Freedom for Operators! |
+ - / * ^ % < > <= >=
And others. These operators support infix syntax, the benefits of
which I believe, in accord with Lispers everywhere, are overrated, but
this post is not about infix expressions. It is about the peculiar
and unnecessary distinction between operators and functions. That is,
in Javascript, we are unable to say something as reasonable as:reduce(+, [1,2,3,4])
Even though nothing about the nature of + dictates that this ought
to be verboden. On the contrary, given an array and a + function,
this is about the most reasonable thing you could want to do with
them. Why this state of affairs persists in modern programming
languages I will not presently speculate. Operators in Gazelle
The unusual status of these functions in Javascript poses a problem for Gazelle, which tries to graft a Lisp-like language onto it. In all Lisps I know of, the operations listed above are exposed to the user as plain functions, so that one can write:(reduce + (list 1 2 3 4))
For instance. Ultimately, I feel that in day to day programming its
indispensable to have basic operations be functions. Parenscript,
which is otherwise a great piece of software, lets you write:(+ 1 2 3 4)
which lulls you into a false sense of security pertaining to the
nature of +, but produce code which results in an error if you
write:(apply #'+ (list 1 2 3 4))
Because + is not a function. Gazelle takes a somewhat more
conservative approach. Without loading any other code, there is no
+ operation and you cannot write even (+ 1 2). What you can do is refer to the underlying Javascript operator using the notation Gazelle uses for Javascript primitives, eg:
_+. One
can write:(_+ 1 2)
But cannot write (_+ 1 2 3 4). Why not? Because the idea of the
primitive operations is to expose, as closely as possible, the
behavior of the underlying Javascript. The Javascript + operator is
a binary operator, and so the Gazelle _+ operator is also one. Getting Operator Functions in Gazelle
Because of the way that Gazelle works, you can write operator functions pretty easily, but it is a bit confusing as to what is going on, so lets go through it. Suppose we want a function denoted by+
in Gazelle, which is like a Lisp + function. Here is how we might
write it:(define (+)
(_if (_=== 0 (.. arguments length))
((_throw "Plus requires at least one argument.")))
(var total [arguments 0])
(for ((var i 1) (_< i (.. arguments length)) (set! i (_+ i 1)))
(set! total (_+ total [arguments i])))
total)
Where this is almost pure Javascript. This renders into the
following:
var plus = function () {
if ((0===(arguments.length))) {
throw ("Plus requires at least one argument.");
};
var total = arguments[0];
for (var i = 1;(i<(arguments.length));i = (i+1)) {
total = (total+(arguments[i]));
};
return (total);
}
Note that at the level of Javascript, the function we just defined is called
plus, not +. And note that all the references to _+ in
the body have been transcoded to + in Javascript. If we refer to
+ in Gazelle, we refer to plus in Javascript, and if we refer
to _+ in Gazelle, we refer to + in Javascript. Hence, we can go
about our business using + in Gazelle and everything works.A Systematic Solution
In 'idiomatic' Gazelle, which, since I am the world's only Gazelle programmer, means however I program, one is supposed to use modules, and one of the most important modules is theoperator-functions
module, which defines all the common operators as functions and/or
macros. One writes:(require (("hooves/operator-functions" :all))
(+ 1 2 3))
To use all of the definitions in the module. Sometimes, as in the Tampermonkey code, we cannot easily use the module system, because we want to write standalone scripts. In that case you can either get by with simply using the primitive operations or you can now say:
(gazelle:essentials)
at the top of the file, which is a "built-in" macro (defined in
proper.el) that expands to definitions of all the common operators.
This is a reasonable solution if you need to write a standalone script
or otherwise don't like the module system. Feel free to implement
your own solutions. That is what Lisp is all about.

No comments:
Post a Comment