[racket] Why internal definitions?
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/