[racket] Why internal definitions?

From: Neil Van Dyke (neil at neilvandyke.org)
Date: Wed Nov 16 18:21:16 EST 2011

Mark Engelberg wrote at 11/16/2011 02:22 PM:
> I frequently find myself wishing that you could use internal
> definitions in cond without introducing additional indentation, for
> example something like:

One neat thing about Racket is that you can implement new syntax, try it 
out, use it in your projects, put it into PLaneT for other people to 
try, make your own "#lang" that includes all your syntax changes, etc.

A quick proof-of-concept of your requested feature is shown below.  
Pardon me for using "syntax-rules", and for not really testing.

Also, I don't know why the Macro Stepper in Racket 5.2 does not want to 
expand the recursive uses of "%cond/bind:2" for me, but the compiler is 
happy with it.

#lang racket/base

;; TODO: Rewrite this in "syntax-case" or "syntax-parse".

(define-syntax %fake-syntax-error
   (syntax-rules (never) ((_ never) (error))))

(define-syntax cond/bind
   (syntax-rules (else)
     ((_ NON-ELSE-CLAUSE0 ... (else ELSE-EXPR0 ...))
      (%cond/bind:2 (NON-ELSE-CLAUSE0 ...)
                    (ELSE-EXPR0 ...)))
     ((_ NON-ELSE-CLAUSE0 ...)
      (%cond/bind:2 (NON-ELSE-CLAUSE0 ...)

(define-syntax %cond/bind:2
   (syntax-rules (=> define else)
     ;; We've run out of non-"else" clauses, so finish.
     ((_ () (ELSE-EXPR0 ...))
      (begin ELSE-EXPR0 ...))
     ;; Next clause is an "else", which must not have been the last 
clause, so error.
     ((_ ((else X ...) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
      (%fake-syntax-error "cond/bind: else clause is only permitted at 
end" (else X ...)))
     ;; Next clause is a "define".
     ((_ ((define VAR EXPR) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
      (let ((VAR EXPR))
        (%cond/bind:2 (NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)))
     ;; Next clause is an invalid "define".
     ((_ ((define JUNK0 ...) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
      (%fake-syntax-error "cond/bind: invalid define syntax" (define 
JUNK0 ...)))
     ;; Next clause is a "=>".
      (let ((val TEST-EXPR))
        (if val
            (PROC-EXPR val)
            (%cond/bind:2 (NON-ELSE-CLAUSE1 ...) ELSE-EXPRs))))
     ;; Next clause has a "=>" erroneously, so error.
     ((_ ((TEST-EXPR => JUNK0 ...) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
      (%fake-syntax-error "cond/bind: syntax error with =>" (TEST-EXPR 
=> JUNK0 ...)))
     ;; Next clause has test expression only.
      (or TEST-EXPR
          (%cond/bind:2 (NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)))
     ;; Next clause is a normal one.
      (if TEST-EXPR
          (begin THEN-BODY0 ...)
          (%cond/bind:2 (NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)))
     ;; Next clause did not match anything else, so error.
      (%fake-syntax-error "cond/bind: invalid clause" NON-ELSE-CLAUSE0))))

;; Examples:

(define (fun-for-list l)
     [(null? l)   'is-null]
     (define fst (car l))
     [(even?  fst) 'is-even]
     [(odd?   fst) 'is-odd]))

(define (foo l)
     [(null? l)  'is-null]
     (define fst (car l))
     [(even?  fst) => (lambda (v) (list 'is-even v))]
     [(zero? 777)]
     [else         'is-else]))


Posted on the users mailing list.