
@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: