[plt-scheme] And now for an actual Scheme question (PLAI)

From: Eli Barzilay (eli at barzilay.org)
Date: Thu Jul 17 03:09:19 EDT 2008

On Jul 16, Gregory Woodhouse wrote:
> I've been away from scheme for awhile, so I decided to go back to  
> PLAI and start reading from the beginning
>   I implemented the predicate AE? (for arithmetic expressions) like this
>    ;;pattern based evaluator (language: AE)
>    (define (AE? exp)
>      (match exp
>        ((? number? exp) #t)
>        ((list '+ (? AE?) (? AE?)) #t)
>        ((list '- (? AE?)) #t)
>        ((list '- (? AE?) (? AE?)) #t)
>        ((list '* (? AE?) (? AE?)) #t)
>        ((list '/ (? AE?) (? AE?)) #t)
>        (else #f)))
> So far, so good, but if I follow the model in the book (minus the use  
> of type-case, which doesn't seem to be part of PLT Scheme)

It's included in a separate package that you can download from the
book's page.  (Look for "Get the Software".)

> I end up with something like this
> (define (evaluate exp)
>    (with-handlers
>        ((exn:fail:user?
>          (lambda (exn) (printf "~a~n" exn))))
>    (match exp
>      ((? number? exp) exp)
>      ((list '+ (? AE? t1) (? AE? t2)) (+ (evaluate t1) (evaluate t2)))
>      ((list '- (? AE? t1) (? AE? t2)) (- (evaluate t1) (evaluate t2)))
>      ((list '* (? AE? t1) (? AE? t2)) (* (evaluate t1) (evaluate t2)))
>      ((list '/ (? AE? t1) (? AE? t2))
>       (let
>           ([ n (evaluate t1)]
>            [d (evaluate t2)])
>         (if (equal? d 0)
>             (raise-user-error "division by zero")
>             (/ n d))))
>      (else (raise-user-error "Unable to evaluate expression" exp)))))
> Now, on the face of it, this seems awfully wasteful because I'm
> repeating all the pattern matching that I had to go through to
> identify an expression as an AE in the first place.

Speed should not be a concern when you read the book.  Bugs are much
more important.  For example -- you have a bug in the above code.  You
can spend a few minutes looking for it, but if you had been using
`define-type' and `type-case' you wouldn't have had it in the first
case.  (The bug is in your subtraction case, BTW.)

The main feature of using these construct is how they make your life
easier in a similar way to using a statically-typed language: when you
change the type definition, you will get syntax errors if you don't
change all uses of `type-case' accordingly, which will avoid the kind
of bugs that would just be a distraction.  (You'll still have plenty
of real bugs -- the ones you'll learn from.)

> My next step was going to be parsing the expression into a bunch of
> tagged elements (so I'd only need to read the tag).  For example (+
> 2 3) would be parsed as (('builtin '+) ('num 2) ('num 3)).

(That would get you closer to a re-implementation of the above

> (Oh, if you're wondering about the use of with-handlers, I've
> wrapped this all in a REPL loop, and I don't want to be kicked out
> because of a typo or division by zero or some such thing.)

If you flip quickly through the pages you'll see that a REPL is not
going to be too helpful -- most code will be in the form of big
expressions, and trying them out in a REPL is going to be much less
convenient than using the definitions window.

My bottom line would be to not spend any time with all these
technicalities, just go with the book and things will be easier.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!

Posted on the users mailing list.