Closed nilsbecker closed 6 years ago
In ppx_stage
, values defined outside of a [%code ...]
block are not automatically available inside a [%code ...]
block. To use something defined outside of a [%code ...]
block inside one, you need to first turn it into a value of type 'a code
(which as you've spotted can be done either with Lift.foo
or with another [%code ...]
block, which evaluate their contents at different times), and then splice that 'a code
value into the block using [%e]
.
It's a deliberate decision not to automatically let all values enter [%code ...]
blocks, because I want every value of type 'a code
to be printable as source without referring to unprintable values (MetaOCaml takes a different approach).
In the map
example, the variable x
is actually defined inside a [%code ...]
block and is being used inside another [%code ...]
block.
I'm closing this because I don't think there's actually a bug here, but feel free to keep commenting and/or reopen if I haven't answered the questions.
yes, closing is fine, thanks for the explanation. it was helpful to see the reasoning behind the scoping rules.
about the map
example: it's true that x
is defined inside a %code
block but then it is used in a further, nested %code
block. this means the semantics are not the same within some nesting level of %code
block >0, and outside of the outermost code block. this is what threw me off (and i find it not maximally elegant). as you explained there is a reason for it though.
To understand the scoping rules for staged programs, it's helpful to assign "levels" to every expression. Level 0 is the program being run and level 1 is the program being generated. [%code exp] interprets exp
at a level one higher than the surrounding code, and [%e exp] interprets exp
at a level one lower. The scoping rule is that variables must be used at the same level at which they are declared. In the map example, x
is declared and used at level 1 (once inside [%code ...], and once inside [%code [%e [%code ...]]]).
ah, that's helpful thanks. now i'm getting somewhere.
hi, sorry likewise for using the bug format. i don't get something. i tried this:
this fails with
unbound value s
. i understand that i can fix this bythis one does not evaluate the
!
; later reassignment tor
will change the result.alternatively, i can use
Lift.string
on the firsts
definition, which will evaluate!
.so basically my questions are:
why does the first version not work? is this an implementation problem or would it not be sound?
why is this different from the
map
example in the README, wherex
does extend into the%code
scope?