The dark corners of rep
- From: Eli Barzilay <eli barzilay org>
- To: General discussion about sawfish wm <sawfish-list gnome org>
- Subject: The dark corners of rep
- Date: Tue, 12 May 2009 20:56:17 -0400
On May 12, Christopher Roy Bratusek wrote:
> Am Dienstag, den 12.05.2009, 13:58 +0900 schrieb Teika Kazura:
> > One more bad point is there: not for dev, but that users of
> > Sawfish have to learn Rep.
>
> ... if we switch they'll have to learn <xyz> instead of rep, that
> not a valid point against rep in favour of lisp/scheme.
It is a valid point against rep (are there any books about rep? anyone
uses it outside of sawfish?). Even more: it is a *major* point
against it. Scheme and Lisp systems can be very flexible, and it's
easy to come up with a language that is scheme- or lisp-like (just
using sexpr syntax for that is enough). If the semantics of the
language is far enough from scheme or lisp, then you still have a
different language, despite the superficial resemblance.
The thing with rep is that it's somewhere between Scheme, Lisp, and
ELisp. This is a very bad thing -- more than just the lack of books
to learn it (I'm sure that most people just read about scheme or lisp
or elisp, but they're all different languages from rep).
Here's a list of some obvious problems I ran into. I don't know if
there are many people here who use Scheme or Lisp, but those who do
will probably be horrified by these (and if they tried to program
sawfish, they probably know about some of them).
* No `set!'; uses `setq' and it can be used with new variables
user> (set! x 1)
*** Unbound variable: set!
user> (setq x 1)
1
This is like Lisp and ELisp. There's even `set', which comes from
the dark past of Lisp:
user> (setq x 'y)
y
user> (set x 123)
123
user> y
123
There is no `setf', so it looks like it'll be close to ELisp.
* However, these variables are lexically scoped -- not dynamically
scoped as in Lisp/ELisp:
user> (setq x 123)
123
user> (define (ret-x) x)
user> (let ((x 999)) (ret-x))
123
This is actually a very important point -- rep is lexically scoped
(which is good), which means that it has closures, and `lambda' is
not just a self-evaluating form:
user> (funcall '(lambda () 1))
*** Invalid function: (lambda () 1)
;; this *does* work in elisp, and in some popular lisps too
* Actually this is another confusing point: rep has `funcall', but it
is not necessary since it has a single namespace. In fact, the
implementation could just as well be in rep instead of in C:
(define (funcall f . xs) (apply f xs))
which is what the C code is doing.
* Also, rep has `defun' and `defvar', but the distinction between them
in lisps is setting the "function value" or the "symbol value" --
this is not something that rep has, so `defun' is mostly syntactic
sugar for `define' with function.
* `defvar', however, still makes the defined name special (dynamically
scoped):
user> (defvar x 1)
x
user> (define (ret-x) x)
user> (let ((x 123)) (ret-x))
123
This has the usual possible catastrophe:
user> (define (foo x) (ret-x))
user> (foo 5)
5
which Common Lisp users solve by always naming special variables
with *stars* (and some compilers will warn you if not).
* Even worse, `defvar' does its magic in a way that shadows possible
later definitions:
user> (defvar x 123)
x
user> (define x 1234)
user> x
123
user> (defun x () 12345)
user> (x)
*** Invalid function: 123
(This behavior is unique to rep, AFAICT.)
* It has Common Lisp's idiom of using `defun' inside a `let' to get a
local binding:
user> (let ((count 0)) (defun count! () (setq count (1+ count))))
user> (list (count!) (count!) (count!))
(1 2 3)
but -- it also does the same with `define':
user> (let ((count 0)) (define (count!) (setq count (1+ count))))
user> (list (count!) (count!) (count!))
(1 2 3)
which is of course not needed, because you can do the usual thing in
scheme:
(define count! (let ((count 0)) (lambda () (setq count (1+ count)))))
* But -- yes, there's another "but" -- it also does what Common Lisp
is doing with multiple `defun's, and it will happily do so with
`define':
user> (let ((count 0))
(define (count!) (setq count (1+ count)))
(define (reset!) (setq count 0)))
user> (list (count!) (count!) (reset!) (count!))
(1 2 0 1)
which happens because `define' is actually more like Lisp's `defvar'
and `defun' in that it has a global effect (which is a surprising
contradiction for a lexically scoped, single-namespace language):
user> (let ((x 1)) (define xx (1+ x)) xx)
2
user> xx
2
*BUT* -- `define' *is* defining something local if it's in a
function's scope:
user> (define (foo x) (define xx (1+ x)) xx)
user> (foo 5)
6
user> xx
*** Unbound variable: xx
which makes rep more like JavaScript. Still `defvar' does have a
global effect:
user> (define (foo x) (defvar xx (1+ x)) xx)
user> (foo 1)
2
user> xx
2
which is just like `setq':
user> (define (foo x) (setq xx (1+ x)) xx)
user> (foo 1)
2
user> xx
2
and let's not forget `set' -- unlike in modern Lisps (which are
lexically scoped except for `defvar'ed bindings), `set' behaves as
it does in a dynamically scoped language:
user> (define (foo x) (define xx 'x) (set xx 33) x)
user> (foo 1)
33
but `eval' behaves as a lexically scoped language:
user> (define x 3)
user> (let ((x 999)) (eval 'x))
3
* There's also a bunch of elisp-isms that make the language appear
more like elisp:
- `concat', not `string-append'
- `mapcar', not `map'
- `?x' syntax for characters, not `#\x'
- `defmacro' macros, no hygiene; `defmacro' syntax as in lisp
(separate argument list)
- "first class" macros (yet another can of worms) that can be passed
around like values (which even elisp can't use directly).
- `print' and `princ', not `write' and `display' (and `write' is
bound to something different)
- `integerp', `stringp', `string=' , etc -- not `integer?',
`string?', `string=?', etc
- doc strings
- elisp-like vectors (bracket syntax, `length', `aref'), unlike
scheme or common lisp
- lisp/elisp-like backquotes (try ``,a and also `backquote' vs
`quasiquote')
and some scheme-isms:
- `number->string', not `number-to-string'
- `call/cc'
- exact rationals
and some of its own features (regexps, threads, IO, modules, and
more).
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]