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 ...)
                   ((void))))))

(define-syntax %cond/bind:2
  ;; (_ NON-ELSE-CLAUSEs ELSE-EXPRs)
  (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 "=>".
    ((_ ((TEST-EXPR => PROC-EXPR) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
     (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.
    ((_ ((TEST-EXPR) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
     (or TEST-EXPR
         (%cond/bind:2 (NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)))
    ;; Next clause is a normal one.
    ((_ ((TEST-EXPR THEN-BODY0 ...) NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
     (if TEST-EXPR
         (begin THEN-BODY0 ...)
         (%cond/bind:2 (NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)))
    ;; Next clause did not match anything else, so error.
    ((_ (NON-ELSE-CLAUSE0 NON-ELSE-CLAUSE1 ...) ELSE-EXPRs)
     (%fake-syntax-error "cond/bind: invalid clause" NON-ELSE-CLAUSE0))))

;; Examples:

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

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


--
http://www.neilvandyke.org/
_________________________________________________
 For list-related administrative tasks:
 http://lists.racket-lang.org/listinfo/users

Reply via email to