-
-
Save masak/4ed7ec0fe455b5e70c0f52eb20cb113a to your computer and use it in GitHub Desktop.
Privmsg explaining setting the OUTER of macro arguments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12:40 <masak> I feel I have finally made some (conceptual) progress with the thing blocking `macro infix:<ff>` | |
12:40 <masak> I'm now hoping a piece of undisturbed time will manifest so that I can implement it | |
12:41 <masak> it's not an easy thing, but it's necessary | |
12:44 <sergot> what's the progress ? | |
12:44 <sergot> I mean, what is the problem? | |
12:45 <masak> here's an illustration of the problem, with a minimal program: | |
12:45 <masak> macro moo(y) { my x = 1; return quasi { say(x); say({{{y}}}) } }; my z = 2; moo(z) | |
12:46 <masak> take your time -- what should it output? | |
13:05 <sergot> hmm | |
13:05 <sergot> 1\n2? | |
13:05 <masak> correct | |
13:05 <masak> ...why? :) | |
13:06 <sergot> x is obvious, because in this scope we have x = 1; {{{y}}} because it evaluates the argument, which is 2 | |
13:06 <sergot> I don't know if this is the answer you expect :P | |
13:06 <masak> it is | |
13:07 <masak> but the mechanics to get it to work is a bit messier than that | |
13:07 <masak> it's supposed to be hidden from you, so your answer is fine :) | |
13:08 <sergot> what's behind the scenes? | |
13:15 <masak> ok, so | |
13:15 <masak> conceptually, we like to think of the things that happen on the code-text level, like so: | |
13:15 <masak> 1. mark `z`, Ctrl+C | |
13:16 <masak> 2. mark `{{{y}}}`, Ctrl+V | |
13:16 <masak> 3. mark the whole inside of the quasi (with `{{{y}}}` now replaced by `z`), Ctrl+C | |
13:16 <masak> 4. mark `moo(z)`, Ctrl+V | |
13:16 <masak> so the resulting code after the macro becomes `my z = 2; say(x); say(z);` | |
13:17 <masak> waiting for you to nod :) | |
14:03 <sergot> reading | |
14:03 * sergot nods | |
14:18 <masak> :) | |
14:19 <masak> of course, if copy-pasting were all there is to it, the code would not run | |
14:19 <masak> because `x` is not in scope in the mainline | |
14:19 <masak> I'm gonna use a special symbol here to demonstrate what happens instead | |
14:20 <masak> `my z = 2; ⟦say(x); say(⦃z⦄);⟧` | |
14:22 <masak> those ⟦⟧ mean "use the injectile's scope" (recall, the injectile is the thing that's copied from the quasi | |
block) | |
14:22 <masak> and the ⦃⦄ mean "use the macro argument's scope" (that is, the mainline) | |
14:23 <masak> this is typical of a macro expansion/injection: needing to switch into the macro's/quasi's scope, and then | |
back into the mainline's scope here and there | |
14:25 <masak> I guess you can see that we need ⟦⟧ in order to see `x`, and ⦃⦄ in order to (again) see `z` | |
14:27 <masak> the past few weeks I've been thinking about how to get the ⦃⦄ to work | |
14:36 <masak> the main problem is that, at the time the macro runs, there is only one mainline scope: the static one. and | |
that's the wrong one. | |
14:36 <masak> to make that clear, if we don't do anything about that, the output would be "1\nNone\n" | |
14:37 <masak> because at compile time, the value of `z` is None | |
14:37 <masak> that's clearly wrong -- the output *should* be "1\n2\n", like you said | |
15:17 <masak> what needs to happen is: as we enter the mainline at runtime, the ⦃z⦄ thing needs to refresh so that it gets | |
the runtime-mainline's scope as its new OUTER | |
15:18 <masak> then the `z` lookup will find the `z` with the 2 in it | |
15:18 <masak> presto, everyone's happy | |
15:28 <masak> the recent breakthrough I had is I figured out how to do that refresh of the ⦃z⦄ | |
15:30 <masak> basically, the situation is quite similar to what would be needed here: | |
15:32 <masak> sub foo(x) { my y = x + 1; sub bar() { say(y) }; return bar }; say(foo(10)()); say(foo(20)()); | |
15:33 <masak> there's only one sub `bar` in the code, but there are two *values* of `bar`, one for each call to `foo` | |
15:33 <masak> every time we enter `foo`, we need to "refresh" `bar` so that it points to the OUTER frame we just created as | |
we entered `foo` | |
15:34 <masak> ...that's all :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment