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.

Reply via email to