[plt-scheme] a couple of questions
On Jan 20, 2007, at 2:20 PM, Danny Yoo wrote:
>
>
> On Fri, 12 Jan 2007, Gregory Woodhouse wrote:
>
>> I'm trying to write an evaluator in the style of SICP that I hope
>> will be at least somewhat idiomatic.
>
> Hi Greg,
>
>
> Did you get any responses about this yet?
Actually, i thought the question hadn't made it to the list, but in a
response to a separate posting, Matthew Flatt did show me how to use
exn-message to display the message associated with the user exception:
;; safe-eval-strict: expression environment -> value
(define (safe-eval-strict input-val evn)
(with-handlers
((exn:fail:user? (lambda (exn)
((error-display-handler)
(exn-message exn)
exn))))
(eval-strict input-val evn)))
I don't know how I missed it, because I had been searching for a way
to display that message. I was able to find information on the error
display handler, but that was the missing piece.
> Let's take a look.
>
> ... ok. You may be able to avoid mutation here. Let's look at a
> portion of the code:
>
> (let loop ()
> (with-handlers ...
> (printf "~a " main-prompt)
> (set! input-val (read))
> ...))
>
>
> Here is a let loop here with no variables being bound. Every time
> through the loop, though, we're rebinding input-val. This idea can
> be captured by making the input-val a part of the loop's variables:
>
> (let loop ([input-val (begin (printf "~a " main-prompt)
> (read))])
> (with-handlers (...)
> ...))
Yes, I ws trying to get the sequencing right and if I had only
factored out read prompt, as you do below, then this would have been
more obvious (I hope!)
>
> Since we're going to be doing prompting quite a bit, we can then
> pull that prompting code up as a separate function. I'll just call
> it READ-PROMPT for now:
>
> (define (read-prompt)
> (printf "~a " main-prompt)
> (read))
>
Now, WHY I didn't do this...well, that's a mystery!
>
> After this, the program looks a little bit more like:
> ...
>> 1. I don't want to break out of the loop when evaluating an
>> expression like (/ 1 0) but instead report the error and then give
>> the user an opportunity to enter another expression, leaving the
>> environment intact. But, of course, I do want to break out of the
>> loop in case of a programming error on my part, so my handler for
>> exn:fail:user includes (loop) (where loop is the label in named
>> let). I've never encountered code like this, and I wonder if it's
>> even safe, much less idiomatic scheme.
>
> It looks ok to me. I think it can be better, though. You could
> probably push the exception handling closer to the expression
> that's likely to cause havoc, the eval-strict function.
Yes, I think I realized that after my next iteration, but getting the
syntax right was a challenge.
>
> Let's wrap eval-strict with a helper function SAFE-EVAL-STRICT,
> which we'll introduce within the LOOP definition.
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (let loop ([input-val (read-prompt)])
> (define (safe-eval-strict input-val evn)
> (with-handlers
> ((exn:fail:user? (lambda (exn) (printf "Error!~n")
> (loop (read-prompt)))))
> (eval-strict input-val env)))
> ...)
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ....
Ah! I'll bet that I didn't think of this because read-prompt is a
function.
> ...
>
>> 2. The second question involves the environment, which I
>> anticipate storing as a list or perhaps a hash table. To me, it
>> makes more sense for the evaluator to return an updated
>> environment as a value than to have it modify a global value.
>
> Yes. Also, just as in the case with INPUT-VAL, the environment is
> a value that's probably going to follow along in the looping: it
> might be appropriate to pass that around as well. The structure of
> RUN can turn into:
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;
> (define (run)
> (printf "~a (version ~a)~n" evaluator-name evaluator-version)
> (let loop ([input-val (read-prompt)]
> [env '()])
> ...))
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;
What I had been trying to do is maintain a kind of a "global" (or
maybe top-level) environment, so that the user could type in a series
of (define....) statements, so I don't really want a fresh
environment for every evaluation. But this may be overloading the
term environment a bit, because when evaluating an expression, you
really do want a fresh environment.
>
> And now LOOP is actually starting to look a little bit like, well...
>
> http://download.plt-scheme.org/doc/360/html/r5rs/r5rs-Z-H-9.html#%
> _idx_600
>
>
Hmm...This link doesn't work for me, but I'm sure I can chase it down.
>
>> But it also seems that this style could involve a lot of
>> unnecessary copying.
>
> It really depends on how you define environments and how you extend
> them. It's possible to define them so that you take advantage of
> shared structure. That is, rather than a mutable hashtable, you
> can choose a representation that reuses the existing environment
> structure.
Actually, I started thinking about this after reading the first two
sections of ch. 4 of SICP. That being said, my impression was that
the environments in SICP were basically auxiliary data structures
used during the evaluation of a single expression and then discarded.
Maybe I need to take another look.
Actually, there are two other reasons why I'm interested in avoiding
copying -- One is that a potential application I have in mind
involves potentially huge numbers of bindings being "in effect" (tens
of thousands), a small subset of which may actually be uzed in any
one computation. The other is that I'm thinking about sharing some of
these bindings between different threads. (Yes, I know that doesn't
sound very functional!) To be a bit less mysterious about it, I've
been working for some years on a MUMPS based medical information
system known as VistA. I've been unhappy about the lack of clear
semantics for the system, but then I re(?)-discovered Scheme by
picking up a copy of "The Little Schemer", and I was, well, hooked.
As always, thank you for your help!
Gregory Woodhouse
gregory.woodhouse at sbcglobal.net
There's a fine line between optimization
and not being stupid. -- R. Kent Dybvig
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20070120/cdc702b9/attachment.html>