@ianwlarson has joined the channel
Hello, is there any way to use the return value from a yield
statement?
I’m trying to make a generator that can change its state when passed values, but doesn’t necessarily need to be passed values
@ianwlarson the docs for yield
show an example of using the return value from a yield
expression. is there something else you’re asking about? http://docs.racket-lang.org/reference/Generators.html#%28def._%28%28lib._racket%2Fgenerator..rkt%29._yield%29%29
The problem is it that it demands you use the value
ah, you might want to look at call-with-values
.
if you try to NOT use a value, it has arity error
the issue here is the same as the error produced by this code: (define x (values 1 2))
essentially, yield
returns a varying number of values depend on the number of arguments passed to the generator. call-with-values
can handle an arbitrary number of values, whereas define
/define-values
/let
/let-values
only handle a statically-known number of values.
you can, for example, write (call-with-values (lambda () (yield 2)) list)
, and the values passed to the generator will be collected into a list.
I feel like I need a phd to use this language
there’s a values->list
form provided by various utility libraries, perhaps that would be more palatable?
call with values works pretty well
because then I don’t have to unpack the list
I can use a case-lambda with ([() ()’] [(x) ( do something with the value)])
I’m probably misusing this language
Too used to procedural languages
I think it would be cool if yield
returned void
when nothing is passed to the generator
that would make the zero-args case impossible to distinguish from passing a single argument, which is #<void>
.
and it also wouldn’t help at all distinguish between other numbers of arguments.
I think a more pleasant interface would probably be to just produce a list, not multiple values, but some people find multi-valued return “elegant”. I will not comment on that. :)
Does having a let in a named loop have some undesirable interaction over define?
Does the 2nd let cause massive memory growth? If a define was used instead, would it be different?
@ianwlarson after expansion, there is no difference between internal definitions and an equivalent letrec
. in that code, loop
is called in tail position, so there is no memory cost to the recursion.
so its like
internally converted to a let* or a letrec
not converted but in the actual implementation it’s equivalent
no, it actually is converted; my phrasing was a little misleading. see the grammar for fully-expanded programs: http://docs.racket-lang.org/reference/syntax-model.html#%28part._fully-expanded%29
most notably, define-values
and define-syntaxes
are only general-top-level-form
s. neither appears in the grammar for expr
.
I feel like I need a PHD to use this language
to be fair, if you ask a low-level question, you will get a low-level answer. :)
and I’m thankful for it
I just can’t understand it
well, “non-top-level definitions get turned into letrec
internally” is probably a good enough, simpler explanation.
“A reference to a local binding in a fully expanded program has a scope set that matches its binding identifier exactly. ”
this was a line in the thing you linked me
which I believe answers what I asked
:sweat_smile: