Omnigia

August 27, 2007

More on R6RS ratification

Filed under: scheme — Dan Muresan @ 10:24 pm

Given the preliminary results, it looks like R6RS will pass with a 66% margin (I predicted 70% a while ago). Strangely, official results haven’t been announced yet, in violation of the announced schedule. More strangely, everyone seems to be quiet on this delay; I suspect that the nays are hoping for some last-minute deliverance handed down from the Steering Committee, but I’m surprised that the ayes aren’t becoming impatient at this point.

The comments section provides a glimpse into the disastrous effects of a biased electoral process that requires justification from dissenters, but not from approvers. While most of the nays provide a detailed analysis of the draft (usually acknowledging its virtues where applicable), the “yes” camp, where it bothers at all to comment, seems to employ a pretty lax standard (including a few pearls that I won’t quote in order not to offend the authors).

One comment that I found sad, yet funny states that “…Scheme needs a splash of ‘worse is better‘ to move the language standard forward” — coming from a voter from New Jersey, no less.

On a personal note, I almost messed up my ballot. I sent my vote just before the deadline from my registered voter address, but I forgot to change the default email-address field of the ballot. My vote was rejected; I sent a corrected ballot, but only after the deadline, so it wouldn’t count. I e-mailed Alan Bawden, who mentioned that “I did fix a lot of people’s ballots in trivial ways… [including]… unbalanced parentheses, but I drew the line at actually altering people’s claimed identities” (the email-address field apparently taking precedence over the originating address in the email envelope). Luckily, my vote was accepted after a short back-and-forth.

Update: the Steering Committee has ratified R5.97RS.

August 7, 2007

Emacs Lisp vs. Scheme: scoping and globals

Filed under: scheme, cpscm, emacs — Dan Muresan @ 3:46 am

I’ve been considering an elisp back-end for CPSCM (so that we can program Emacs in R5RS Scheme). I thought the lack of lexical scoping would prove a major stumbling block, but in the end it turns out that Elisp will be somewhat easier to support than Common Lisp. Here are the twists and turns (to evaluate Elisp code, go to the *scratch* buffer, paste the code and type C-x C-e):

  • Elisp has dynamic scope by default:
    (defun f () y)
    (let ((y 10)) (f))  ;; 10
    ;; lambda arguments are also dynamic
    (funcall (lambda (y) (f)) 11)  ;; 11
    
  • However, with (require 'cl) you get access to the (lexical-let …) macro, which does exactly what the name says (there is also a lexical-let*)
  • Using lexical-let, one can easily define lexical-lambda — here’s a simple version (optimized for minimal line lengths, not Lisp-ness)
    (defmacro lexical-lambda (args &rest body)
      (lexical-let* ((r '&rest) (g (lambda (x) (if (eq x r) x (gensym))))
                     (gvars (mapcar g args))
                     (bnd (mapcar* #'list args gvars)))
        `(lambda ,gvars
           (lexical-let ,(delete-if (lambda (b) (eq (car b) r)) bnd)
             ,@body))))

OK, so we’ve played catch up with Common Lisp and managed to work around dynamic scoping; here’s the beautiful part:

  • Elisp has sane(r) globals (from a Schemer’s POV, at least)

To those who haven’t bashed their heads against this problem, Common Lisp’s “normal” way of declaring globals (defvar / defparameter) makes variables “pervasively special” (i.e. dynamic) — meaning that

(defvar myvar 10)
(defun (f) myvar)
(defun g () (let ((myvar 1)) (f)))
(g)  ;; => 1, not 10

This is not such a problem for Lisp, but what with Scheme being a Lisp-1, translation of global functions is problematic:

(define (f x) x)  ;; Scheme
;; Lisp translation -- broken
(defvar f (lambda (x) x))

There’s another standard-compliant way to simulate globals in Lisp (using symbol macros — search comp.lang.lisp for deflex); however this method requires you to define each global before referencing it, which would preclude mutually-recursive global functions:

(deflex f (lambda (x) (funcall g (- x 1))))  ;; broken: g undefined
(deflex g (lambda (x) (if (> x 0) (funcall f x) 0)))

There are other, more convoluted ways to implement “non-special” globals that have elicited endless (and inconclusive, as far as I could tell) threads on comp.lang.lisp, e.g. using (locally (declare (special myvar))). Finally, in many Lisp's one can simply use (setq myvar …) and at most get a warning, but this is not standards-compliant.

As luck would have it, setq globals work in Elisp too, and the manual seems to indicate that this is intended semantics, not accident. So this will save me the pain of working around Common Lisp’s “special” variable rules (I’ve never found a satisfactory solution), which is why I’m happy about Elisp.

Of course there are areas that need work, e.g. an easier “FFI” to access Elisp functions from Scheme (currently, one has to define a CPS-style wrapper in the back-end with the proper mangled name to make a function callable from CPSCM). But I find the prospect of programming Emacs in Scheme a pretty good motivation…

[ Powered by WordPress ]