Thinking about your example again, is the idea here to preserve the
first (so perhaps outermost) continuation mark information, instead of
the innermost continuation mark? I don't yet fully understand how this
approach interacts with the evaluation of tail position expressions,
but keeping both seems pretty useful.
Regarding the (* (loop (sub1 n)) n) information, as I understand
errortrace does wrap subexpressions. Here is the instrumentation
result of (* (loop (sub1 n)) n):
(with-continuation-mark ek:errortrace-key '((* (loop (sub1 n)) n) SRCLOC)
(#%app
*
(with-continuation-mark ek:errortrace-key '((loop (sub1 n)) SRCLOC)
(#%app
loop
(with-continuation-mark ek:errortrace-key '((sub1 n) SRCLOC)
(#%app sub1 n))))
n))
A guess is that the continuation mark value '((loop (sub1 n)) SRCLOC)
is being overwritten by its subsequent evaluation to (* (loop (sub1
n)) n). This provides error-centric backtrace information.
What I can think about the effect of keeping only the outermost
continuation mark is that the control-flow information w.r.t. tail
expressions will be lost. In the following (unreal) example, there
will be no chance to identify which (/ y 0) caused the error.
On Mon, Jul 27, 2020 at 1:13 PM Shu-Hung You <[email protected]> wrote:
>
> By changing (fact 5) to (* 2 (fact 5)), the stack information becomes
>
> /: division by zero
> errortrace...:
> /Volumes/ramdisk/fact.rkt:6:17: (/ 1 0)
> /Volumes/ramdisk/fact.rkt:7:12: (* (loop (sub1 n)) n)
> /Volumes/ramdisk/fact.rkt:7:12: (* (loop (sub1 n)) n)
> /Volumes/ramdisk/fact.rkt:7:12: (* (loop (sub1 n)) n)
> /Volumes/ramdisk/fact.rkt:7:12: (* (loop (sub1 n)) n)
> /Volumes/ramdisk/fact.rkt:7:12: (* (loop (sub1 n)) n)
> /Volumes/ramdisk/fact.rkt:9:0: (* 2 (fact 5))
>
> Here, the difference is that (fact 5) is no longer at tail position. I
> believe errortrace is aiming at preserving proper tail implementation
> behavior.
>
> On Mon, Jul 27, 2020 at 11:39 AM Sorawee Porncharoenwase
> <[email protected]> wrote:
> >
> > (By "integrating" with the new strategy, I meant having two keys: one for
> > the new strategy and one for the old strategy. I can see that the first
> > entry of the old strategy is useful, and it's missing in the new strategy).
> >
> > On Sun, Jul 26, 2020 at 8:21 PM Sorawee Porncharoenwase
> > <[email protected]> wrote:
> >>
> >> Hi everyone,
> >>
> >> I have a question about the implementation of errortrace.
> >>
> >> Consider the classic factorial program, except that the base case is buggy:
> >>
> >> (define (fact m)
> >> (let loop ([n m])
> >> (cond
> >> [(zero? n) (/ 1 0)]
> >> [else (* (loop (sub1 n)) n)])))
> >>
> >> (fact 5)
> >>
> >> Running this program with racket -l errortrace -t fact.rkt gives the
> >> following output:
> >>
> >> /: division by zero
> >> errortrace...:
> >> /Users/sorawee/playground/fact.rkt:9:17: (/ 1 0)
> >> /Users/sorawee/playground/fact.rkt:10:12: (* (loop (sub1 n)) n)
> >> /Users/sorawee/playground/fact.rkt:10:12: (* (loop (sub1 n)) n)
> >> /Users/sorawee/playground/fact.rkt:10:12: (* (loop (sub1 n)) n)
> >> /Users/sorawee/playground/fact.rkt:10:12: (* (loop (sub1 n)) n)
> >> /Users/sorawee/playground/fact.rkt:10:12: (* (loop (sub1 n)) n)
> >>
> >> I find this result subpar: it doesn’t indicate which call at the top-level
> >> leads to the error. You can imagine another implementation of fact that
> >> errors iff m = 5. Being able to see that (fact 5) at the top-level causes
> >> the error, as opposed to (fact 3), would be very helpful.
> >>
> >> Not only that, (* (loop (sub1 n)) n) also looks weird. There’s nothing
> >> wrong with multiplication, so I don’t find this information useful.
> >>
> >> The tail-recursive factorial is similarly not helpful:
> >>
> >> (define (fact m)
> >> (let loop ([n m] [acc 1])
> >> (cond
> >> [(zero? n) (/ 1 0)]
> >> [else (loop (sub1 n) (* n acc))])))
> >>
> >> (fact 5)
> >>
> >> produces:
> >>
> >> /: division by zero
> >> errortrace...:
> >> /Users/sorawee/playground/fact.rkt:9:17: (/ 1 0)
> >>
> >> ________________________________
> >>
> >> I have been toying with another way to instrument the code. It roughly
> >> expands to:
> >>
> >> (define-syntax-rule (wrap f)
> >> (call-with-immediate-continuation-mark
> >> 'errortrace-k
> >> (λ (k)
> >> (let ([ff (thunk f)])
> >> (if k
> >> (ff)
> >> (with-continuation-mark 'errortrace-k 'f
> >> (ff)))))))
> >>
> >> (define (handler ex)
> >> (continuation-mark-set->list (exn-continuation-marks ex) 'errortrace-k))
> >>
> >> (define (fact m)
> >> (wrap (let loop ([n m])
> >> (wrap (cond
> >> [(wrap (zero? n)) (wrap (/ 1 0))]
> >> [else (wrap (* (wrap n) (wrap (loop (wrap (sub1
> >> n))))))])))))
> >>
> >> (with-handlers ([exn:fail? handler])
> >> (wrap (fact 5)))
> >>
> >> which produces:
> >>
> >> '((loop (wrap (sub1 n)))
> >> (loop (wrap (sub1 n)))
> >> (loop (wrap (sub1 n)))
> >> (loop (wrap (sub1 n)))
> >> (loop (wrap (sub1 n)))
> >> (fact 5))
> >>
> >> This result is more aligned with the traditional stacktrace, and gives
> >> useful information that I can use to trace to the error location.
> >>
> >> It is also safe-for-space:
> >>
> >> (define (fact m)
> >> (wrap (let loop ([n m] [acc 1])
> >> (wrap (cond
> >> [(wrap (zero? n)) (wrap (/ 1 0))]
> >> [else (wrap (loop (wrap (sub1 n)) (wrap (* n
> >> acc))))])))))
> >>
> >> (with-handlers ([exn:fail? handler])
> >> (wrap (fact 5)))
> >>
> >> produces:
> >>
> >> '((fact 5))
> >>
> >> Now, the question: why is the current errortrace implemented in that way?
> >> Am I missing any downside of this new strategy? Would switching and/or
> >> integrating with the new strategy be better?
> >>
> >> Thanks,
> >> Sorawee (Oak)
> >
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send an
> > email to [email protected].
> > To view this discussion on the web visit
> > https://groups.google.com/d/msgid/racket-users/CADcuegto9%2BDtFTwAVmiReOcCwpARzBSbFhF0knyexb7UhoHQiA%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/racket-users/CAMTzy%2BanqswT3C2MpDUb%2BxEJAoAre%2B8Uj-UEMRd-i%3DPfFyV0Sg%40mail.gmail.com.