Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Redefining if

3 views
Skip to first unread message

Brian Campbell

unread,
Mar 9, 2002, 2:31:21 AM3/9/02
to
I have written a macro which I would like to use to replace if. It uses
if in it's expansion, however, so I can't call it if. If I were writing
a function to redefine car, but I needed to use car in it's definition,
I could just write

(define old-car car)

But if I try writing

(define-syntax old-if
(syntax-rules ()
((_ stuff ...) (if stuff ...))))

my new definition for if will shadow the old if, and so when old-if is
expanded, I will actually get my new one, and I'll get into an infinite
loop of macro expansion. Is there any way to save the value of a special
form or macro in order to redefine it? If there is no portable way, is
there a way in MzScheme 200alpha12?

For reference, here is my new if. It's actually somewhere between cond
and if. The idea was borrowed from Paul Graham's description of his new
Arc language, although I decided I liked the => idea better than binding
the variable "it" and I would rather type if than cond, since it's
shorter. I also find that I frequently write an if statement, and a
minute later want to change it into a cond, so it's nice if they are
both rolled into one.

(define-syntax if*
(syntax-rules (=>)
((_) (if #f #f))
((_ exp) exp)
((_ test => exp more ...) (let ((val test))
(if val
(exp val)
(if* more ...))))
((_ test exp more ...) (if test exp (if* more ...)))))

--
Brian Campbell
Real email: lambda (at) cs (dot) dartmouth (dot) edu

William D Clinger

unread,
Mar 9, 2002, 1:25:31 PM3/9/02
to
Brian Campbell wrote:
> Is there any way to save the value of a special
> form or macro in order to redefine it?

No, not in general. In your particular case, though, you could
write your macro to use COND instead of IF. Redefining IF isn't
supposed to affect the semantics of COND in R5RS Scheme, and it
doesn't in the current development version of Larceny (the only
system I tried).

Here's a solution for your particular case that might be more
portable in practice, though less portable in theory. Define
a procedure like

(define (thunkified-if bool then-thunk else-thunk)
(if bool
(then-thunk)
(else-thunk)))

and then define your macro to thunkify the appropriate forms and
call thunkified-if instead of using IF directly. This won't work
in pure interpreters that defer macro expansion to call time, but
most people use systems that expand macros ahead of time.

> If there is no portable way, is
> there a way in MzScheme 200alpha12?

I don't know.

Will

Shriram Krishnamurthi

unread,
Mar 10, 2002, 8:06:54 PM3/10/02
to
There are 2 top-level s-exprs of code in this message. The first is
patarc.scm. The second defines arc-helpers.scm, on which the first
depends. If you save each one appropriately, you can then run the
following code in the patarc language of DrScheme v200a. Note that it
implements some of the Arc primitives you are interested in.

(if 2 it)
==> 2

Shriram

----------------------------------------------------------------------

(module patarc mzscheme

(require-for-syntax "arc-helpers.scm")

(provide #%top
(rename arc-if if)
(rename arc-do do)
(rename arc-cond cond)
(rename arc-plus +)
(rename arc-fn fn)
(rename pat-match match)
(rename pat-module-begin #%module-begin)
(rename pat-datum #%datum)
)

(define-syntax (arc-if expr)
(syntax-case expr ()
[(_ test then)
(syntax (arc-if test then (void)))]
[(_ test then else)
(with-syntax ([it-id (implicit-identifier (syntax test) 'it)])
(syntax (let ([it-id test])
(if it-id then else))))]))

(define-syntax (arc-do expr)
(syntax-case expr ()
[(_ e ...)
(syntax (begin e ...))]))

(define-syntax (arc-cond expr)
(syntax-case expr ()
[(_)
(syntax (void))]
[(_ q0 a0 rest ...)
(syntax (arc-if q0
a0
(arc-cond rest ...)))]))

(define-syntax (arc-fn expr)
(syntax-case expr ()
[(_ vars bodies ...)
(syntax (lambda vars bodies ...))]))

(define-syntax (arc-rfn expr)
(syntax-case expr ()
[(_ name args bodies ...)
(syntax (letrec ([name (lambda args
bodies ...)])
name))]))

(define (arc-plus . args)
(if (null? args)
0
(let ([first (car args)])
(cond
[(number? first) (apply + args)]
[(string? first) (apply string-append args)]
[(vector? first) (apply vector-append args)]
[(list? first) (apply append args)]
[else (error '+ "don't know what to do with ~s~n"
first)]))))

(define vector-append
(let ([empty-vector (vector)])
(case-lambda
[() empty-vector]
[(x) x]
[args (apply vector
(apply append
(map vector->list args)))])))

(define-syntax pat-module-begin
(syntax-rules ()
[(_ E) (#%module-begin E)]))

(define-syntax pat-datum
(syntax-rules ()
[(_ . E) (#%datum . E)]))

(define-syntax (pat-match expr)
(syntax-case expr (->)
[(_) (syntax (void))]
[(_ pat -> action rest ...)
(syntax
(let ([line "the input line"])
(if (regexp-match line pat)
action
(pat-match rest ...))))]))

)

----------------------------------------------------------------------

(module arc-helpers mzscheme

(provide implicit-identifier)

(define (implicit-identifier original-context-id new-id-sym)
(datum->syntax-object original-context-id new-id-sym))

)

David Rush

unread,
Mar 12, 2002, 4:20:39 AM3/12/02
to
Brian Campbell <lambd...@yahoo.com> writes:
> I have written a macro which I would like to use to replace if.

Don't do it. This is one of those cases where you want to adhere to
the principle of least surprise. Anyone coming behind you to read your
code will curse you for overloading IF.

> For reference, here is my new if. It's actually somewhere between cond
> and if.

It's COND with the extra grouping notation lifted.

> it's nice if they are both rolled into one.

Well it's not horrible, but then again I tend to think of COND as the
primary control operator so I probably don't feel the need. Don't get
me wrong, there are whole SRFIs based on sillier ideas than this. If
it works for you, fine. Overloading primitive operators is *such* a
bad idea, regardless of the language. Someone always ends up with far
more pain than is saved by overloading...

> (define-syntax if*
> (syntax-rules (=>)
> ((_) (if #f #f))
> ((_ exp) exp)
> ((_ test => exp more ...) (let ((val test))
> (if val
> (exp val)
> (if* more ...))))
> ((_ test exp more ...) (if test exp (if* more ...)))))

IF* is a perfect name for it. There is a long habit in the Scheme
world to name extended/syntactic-sugared things with a '*' suffix on
the archetype name.

david rush
--
There is only one computer program, and we're all just writing
pieces of it.
-- Thant Tessman (on comp.lang.scheme)

0 new messages