The Sweetest Sugar

Stumbled upon this curious syntax in a talk by Sussman:

  (define ((f x) y) ...)

In standard Scheme:

  (define (name . args) . body)

means:

  (define name (lambda args . body))

In the past, I’ve implemented (define name . body) syntax in a few evaluators as:

  // Pseudo-C
  eval(env, expr) {
    ...
    if ( car(expr) == s_define ) {
      name = cadr(expr);
      body = cddr(expr);
      if ( pairQ(name) ) {
        return define(env, car(name), lambda(env, cdr(name), body));
      } else {
        return define(env, name, car(body));
      }
    }
    ...
  }

I was so wrong… the expansion of define should recur if name is a pair:

  eval(env, expr) {
    again:
    ...
    if ( car(expr) == s_define ) {
      name = cadr(expr);
      body = cddr(expr);
      if ( pairQ(name) ) {
        expr = list(s_define, car(name), cons(s_lambda, cons(cdr(name), body)));
        goto again;
      } else {
        return define(env, name, cadr(body));
      }
    }
    ...
  }

Example:

(define (((sequence op) start constant) . rest)
  (let ((result start))
    (set! start (op start constant))
    result))
(define arithmetic (sequence +))
(define geometric (sequence *))
(map (arithmetic 1 3) '(1 2 3 4))
  ;;  => (1 4 7 10)
(map (geometric 1 2) '(1 2 3 4))
  ;; => (1 2 4 8)

Expansion:

(define (((sequence op) start constant) . rest)
  (let ((result start))
    (set! start (op start constant))
    result))
=>
(define ((sequence op) start constant)
  (lambda rest
    (let ((result start))
      (set! start (op start constant))
      result)))
=>
(define (sequence op)
  (lambda (start constant)
  (lambda rest
    (let ((result start))
      (set! start (op start constant))
      result))))
=>
(define sequence
  (lambda (op)
  (lambda (start constant)
  (lambda rest
    (let ((result start))
      (set! start (op start constant))
      result)))))

Sweet!!

Leave a Reply

Your email address will not be published. Required fields are marked *

*