On Scheme

Thoughts on Scheme and teaching Scheme

An if extension

Posted by Peter on March 7, 2006

I have noticed that the if statement can be a bit tricky for the new programmer. Not because they don’t understand how it works, but because they wish to put more than one statement for the positive or negative clause, especially when debugging. I am reluctant to direct a new student to the more complicated looking cond, and likewise begin can make their programs too intimidating.

My solution was to create a new if, the lif, which separates the positive clause from the negative with an else, here is an example of what it should look like in actions:

(lif (null? x)
  (display x)
  #f
  else
  (display (cdr x))
  #t)

Initially I thought this would be an easy task, but scheme’s pattern matchers in their macros will only accept one at a given level of nesting, so I was forced to write an intermediate macro called lif-i

  (define-syntax lif-i
    (lambda (x)
      (syntax-case x (else)
        (
          (lif-i condition else (neg ...))
          (syntax (unless condition (begin neg ...)))
        )
        (
          (lif-i condition pos ... else (neg ...))
          (syntax (if condition (begin pos ...) (begin neg ...)))
        )
        (
          (lif-i condition pos ...)
          (syntax (if condition (begin pos ...)))
        )
      )))

If we were to use lif-i directly it would look like:

(lif-i (null? x)
  (display x)
  #f
  else
  ((display (cdr x))
  #t))

lif could then be implemented as a macro that collects the statements after an else into a list, and then uses lif-i to do the rest of the work.

  (define-syntax lif
    (lambda (x)
      (let ((lst (cdr (syntax-object->datum x))))
        (letrec ((elser (lambda (l)
                          (cond ((null? l) '())
                                ((eq? (car l) 'else) (list 'else (cdr l)))
                                (else (cons (car l) (elser (cdr l))))))))
          (datum->syntax-object (syntax k) (cons 'lif-i (elser lst)))))))

Advertisements

3 Responses to “An if extension”

  1. You write above that the pattern matcher only accepts one ellipsis (…) in a pattern. Luckily that is not correct.
    Consider:

    (define-syntax foo
    (syntax-rules ()
    [(foo ((a b) …) …)
    (list ‘(a …) … ‘(b …) …)]))

    > (foo ((d 1) (e 2) (f 3)))
    ((d e f) (1 2 3))

    > (foo ((d 1) (e 2) (f 3)) ((g 4) (h 5)))
    ((d e f) (g h) (1 2 3) (4 5))

  2. Peter said

    I meant at a given level of nesting, what I wanted was (foo body1 … else body2 …), but this is not possible, alas. If you read the source you might notice that lif-i uses (lif-i condition pos … else (neg …)) so I obviously knew back then that they can occur at different levels. Why does everyone assume that I don’t try these things out?

  3. I misunderstood what you meant by “at a given level” part. The template in the lif-i example does have two …, but they are separated with parenthesis.

    Why I misunderstood? Well the wording suggested that you meant it was an oversight two elipsis weren’t supported. Allowing it would lead to ambiguities however. For example the pattern (foo body1 … else body2 …) can match (foo 1 2 else 3 4 else 5 6) in two different ways.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: