I think it’s intended. At least it is in line with what I would expect if function, or parametric would give a result that is +nan.0. I would find it weird if there was a line between (–1 0) and (1 0). (plot (function (λ (x) (flsqrt (- (flabs (fl x)) 1))) -2 2))
(then again, I’m biased in this discussion)
Yes, I suspect this was added to support the function
and parametric
renderers. And it is fine for the functions passed to these renderers to return +nan.0
or +/-inf.0
and plot should handle that. The question is whether lines
should do that as well, or rather, whether it is documented behavior for lines
. The fact that function
is internally implemented in terms of lines
is an implementation detail, not a documented API.
I am not suggesting that we change the behavior, just that we don’t document it. That is: • you can plot functions which return +nan.0
or +/-inf.0
, and this behavior will be guaranteed to work in the future • using +nan.0
values in the lines
renderer works now, but you should not rely on it. Than again, if using +nan.0
values for lines
is in wide use already, we might as well document lines as well and put a comment in the code where the “magic” happens to make it explicit, so we make sure we don’t break it.
I don’t mind removing it from the documentation. I would expect lines
to continue functioning this way, but when it doesn’t, as you said, just use lines
twice.
@sorawee Can we view the invocation of the continuation from call/ec as unstacking the call stack until reaching the same context as the call/ec
site? And call/cc
as copying the state as you say? @343519265 Do you happen to have a link to a comparison by any chance?
@laurent.orseau#lang racket/base
(collect-garbage)
(time
(for ([_ (in-range 10000000)])
(call/cc
(λ (k)
(+ 1 (k 0))))))
;cpu time: 487 real time: 487 gc time: 7
(collect-garbage)
(time
(for ([_ (in-range 10000000)])
(call/ec
(λ (k)
(+ 1 (k 0))))))
;cpu time: 794 real time: 794 gc time: 13
Thanks! Do you happen to have BC on the same machine too? :)
No, because in cs I think this is understandable, because call/cc is simply chez call/cc + a few things, while call/ec needs to touch metacontinuation frames additionally
Do you mean that Chez doesn’t have call/ec?
probably call/ec is better when we have plenty of prompts in stack, but i think it is rare.
chez has call/1cc which is efficient for escape, but it seems racketcs didn’t make use of it.
Can’t call/ec be implemented in terms of call/1cc then?
for chez call/ec can be implemented as call/1cc plus dynamic extent checking, but for racket, probably marks, prompts and threads make it complicated. I am not sure
Oh I see, bummer
you could make plot log a debug level message whenever +nan.0
is used with lines
and then build and test every package and any large apps you know of, that might give you a sense of how widespread its use is.
The issue is that the documentation for two new renderers now mentions this behavior explicitely, and the question is whether to keep that in the documentation (and therefore making this feature official) or to leave it out. It is not an essential feature for the renderers themselves either…
Just for reference, this “feature” is part of the plot-device, and not so much of lines etc. But I think there are valid alternatives to get the same result, so I will take it out of the documentation.
Also, chez’s call/cc is fast so the optimizations make less difference
Right. Does that mean that let/cc
is now recommended for simple escape continuations instead of let/ec
?
I think you should still use the same thing if you don’t need full continuations
to make the intent clearer you mean?
And it’s faster on BC and it may be faster on CS
As a first approximation how about there being a new parameter for the error display handler to consult. The parameter is something like a list of module paths to ignore (if an error’s srcloc matches that modpath).
And it defaults to something like “modpaths from ‘main-distribution’”?
Letting a user configure this — or a tool that helps a certain kind of user — might be useful. Similar to why it’s handy to configure logger output.
I don’t think “main-distribution” is the right thing here — “inside the runtime system” seems more likely
OK yes I’m not sure the right default, I’m sure you’re right about htat.
I guess I’m just pointing out the obvious that this is similar to logger output, or to macro-hiding in the step expander. In that, what is good to ignore, depends.
both on general grounds, that “main-distribution” is not intended to be special, and that errors inside plot or pict are not really different from inside other libraries
but yes, I agree with the general point about hiding
It’s really just that, between “beginner” and “core Racket developer”, there are some useful degrees of hiding. Even for the same person, depending on what they’re working on.
I can imagine both function
and lines
compile to line-internal
, which allow NaN, but lines
does not.
For now, I’ve made the easy change of just dropping builtin functions from the trace (disable filtering by setting PLT_SHOW_BUILTIN_CONTEXT
), and we can see whether that’s better or worse.
hello again, i was trying to make a list in a more lispy way while trying to make a list out of tokens given by a lexer from <https://docs.racket-lang.org/br-parser-tools/Lexers.html?q=br-parser-tools|Parser Tools> . i came up with something, that was close to what i remember seeing in the internet. but i realized that it maybe doesn’t count as tail-call recursion, so it probably wouldn’t get optimized? i know in this case i can replace it with for/list or for/fold maybe. but i want to know if there’s a correct way to write this. (define (tokens->list next-token)
(let loop ([r (next-token)])
(cond
[(not (void? (position-token-token r)))
(cons (position-token-token r) (loop (next-token)))]
[else (cons r '())])))
you can see cons
is receiving a loop call as its second argument.
I think the worry about non tail recursion is usually exaggerated. Racket has a “deep stack” feature which allows you to recur however deep as long as there’s enough memory, so what you are doing is perfectly fine.
I seem to recall that a while ago someone investigated tail-recursive and non-tail-recursive versions of some function, and found that the non-tail one ran faster, without them ever hitting memory problems.
ok thank you for the information! once again~
although i was curious if there was a lispy way that was standard for doing accumulation.