|
6macros: discussing the finer points of Perl 6 macros, Qtrees, and how to stay sane | irclog: irclog.perlgeek.de/6macros/today Set by moderator on 28 July 2015. |
|||
|
05:51
cfloare_ joined,
masak_ joined
06:03
cgfbee joined
08:23
vendethiel joined
|
|||
| masak_ | morning | 08:28 | |
| ENOFROGGS | |||
| was gonna tell him that, with synthetic Qtrees, his use case (of having a macro auto-creating a sub just based on the name) is possible | |||
| masak | clumsy-ish (since you have to build a Qtree by hand), but possible | 08:32 | |
| oh, but it gets slightly better because some parts (like the sub body) could be constructed as a quasi | |||
| vendethiel | yes, but you can't refer to it then, can you? | 08:36 | |
| masak | you can't, but that's arguably a bug. | 08:38 | |
| that is, stuff injected by unhygienic mechanisms ought to show up as lexically declared things just as much as stuff that was parsed | 08:39 | ||
| this has to happen at injection-time, that is, after the macro returns and we incorporate its Qtree into the mainline Q | 08:42 | ||
| any unhygienic (=contextless) Q nodes that are also declarations (Q::Statement::My, Q::Statement::Constant, Q::Statement::Sub, more in the future) should trigger a *side effect* of registering a lexical in the static scope | 08:43 | ||
| presumably COMPILING:: could work along the same mechanism, actually | |||
| vendethiel | right | 08:45 | |
| masak | $ perl6 bin/007 -e='macro moo() { return Q::Statement::My { ident: Q::Identifier { name: "foo" }, expr: "James Bond" } }; moo(); say(foo)' | 08:48 | |
| Variable 'foo' is not declared | |||
| vendethiel: if you have the tuit, please file an issue ^ | |||
| vendethiel | done (based off this irclog) | 08:53 | |
| masak | ossum | 08:56 | |
| this *almost* addresses pdcawley's "can I do sinful things with hidden lexical stuff?" | 08:57 | ||
| except they show up too late, after the code sent as arguments to the macro is already parsed | 08:58 | ||
| which means that still, to `is parsed` our hope we put, in a hand-waving fashion | |||
| vendethiel | can do stuff like "map({ it * 2 }, xs)" yet? :P | 09:02 | |
| probably, actually | |||
| masak | that's exactly the thing I'm talking about | 09:06 | |
| in my understanding, no | 09:07 | ||
| the reason `is parsed` is needed there is that something needs to intercept the parser and placate it before it reaches the `it` and cries foul | |||
| that's not possible yet, IMU | |||
| by the way | 09:11 | ||
| I found something interesting as I was building out the `Object { ... }` syntax | 09:12 | ||
| there's one scenario where `Object { ... }` is not identical to `{ ... }` | |||
| and that's when you have overridden "Object" lexically | |||
| which, 007 being super-liberal about that stuff, is a thing | |||
| if you override it with something not-typey, 007 should crash and burn at parse time | 09:13 | ||
| if you define your own lexical class "Object" (not a thing yet), it should use that | |||
| in other words, what's in that type slot by default is not simply an identifier "Object" rooted in the current scope | 09:14 | ||
| it's an identifier "Object" rooted in the built-ins scope | |||
| that is, the same kind of "lexical dislocation" mechanism that's in play with quasis, is also in play here | |||
| not user-exposed (since if you override that slot with anything, you get the default sane lexical semantics), but used by the language itself, at least conceptually | 09:15 | ||
| vendethiel | ah, right | 09:16 | |
| yes indeed, that's exactly the case that doesn't work | 09:17 | ||
| masak | yesterday, I implemented `my s = Str { value: "lol" }`, just for fun/consistency :) | 09:18 | |
| you can even do `my n = None {};` | |||
| vendethiel | well | 09:19 | |
| macro mymelt($s) { return Q::Identifier { name: melt($s) } }; | 09:20 | ||
| masak | indeed | 09:21 | |
| vendethiel | macro it { mymelt("it") }; | ||
| macro map($block, $xs) { quasi { for {{{ $xs }}} -> {{{ Q::Identifier { name: "it" } }}} { {{{ $block }}} } }} | |||
| masak | should we do melt() next, then? should be fairly easy at this point. | ||
| vendethiel | or something? | ||
| masak poners this | |||
| ponders* | 09:22 | ||
| oh, right | |||
| vendethiel | hables espanol? :P | ||
| masak | :P | ||
| no, no hablo | 09:23 | ||
| any kind of parameter, both for blocks and for subs, are also declaration slots | |||
| thanks for reminding me | |||
| vendethiel | right | ||
| masak | but the `macro it` is not enough | ||
| since you're not calling `it` in the map | |||
| it needs to be a macro term or something | |||
| also, calling a macro from macro it does not mean what you think it means :) | 09:24 | ||
| calling a sub from the macro is probably what you wanted | |||
| vendethiel | right | 09:25 | |
| masak | interesting: github.com/tomprimozic/type-systems -- news.ycombinator.com/item?id=10639734 | 09:46 | |
| ok, so melt() can go in the setting | 09:55 | ||
| what would an implementation of it look like? | |||
| which things can we reasonable melt()? | |||
| literals, terms, identifiers, expressions | 09:56 | ||
| and the implementation is really easy: just run .eval($runtime) on the Qtree | |||
| after checking that it has a reasonable type, I guess | |||
| vendethiel | yeah | 09:59 | |
|
10:02
vendethiel- joined
|
|||
| masak | another, less cute name for melt() would be val() | 10:38 | |
| similar in spirit to Perl 6's val() for evaluating "safe things", like literals or constants | 10:39 | ||
| folks, we've now got the melt() built-in | 12:28 | ||
| hope this ups the stakes further to do something cool with 007 macros/quasis/Qtrees :) | |||
| vendethiel- | val is a no-go. it's far too vague | 12:35 | |
| I proposed unwrap, I think? | 12:36 | ||
| also, I'm very interested in trying it out, but I'm also very interested in playing skyrim right now :P. | |||
| masak | aha. :) | 12:39 | |
| don't let me stop you ;) | |||
| I saw the unwrap suggestion (and replied to it) | 12:40 | ||
| it would be an excellent suggestion if it were only literals we were unwrapping | |||
| hup -- travis says I broke master...? :/ | 12:43 | ||
| oh yeah, I broke it. big time. | 12:44 | ||
| missing comma :( | |||
| pushed the comma | 12:45 | ||
| vendethiel- | yes, I remember the issue | 12:46 | |
| "cute" names would include "inner-value", some kind of CAPS function to indicate it's doing introspection (Ć la WHAT/WHY/etc) | 12:47 | ||
| meh, inner-value is bad | |||
| masak | same problem as 'wrap' | ||
| er, 'unwrap' | 12:48 | ||
| it's more dynamic than that -- it actually evaluates variables/constants/expressions | |||
| hm, it actually runs function calls o.O | |||
| hadn't realized | |||
| damn, then it's an eval(), basically | |||
| vendethiel- | of course, it uses the same .eval() | ||
| that's pretty powerful *g* | 12:49 | ||
| maybe a *bit too much* | |||
| masak | yeah, a function call gives access to all the rest | ||
| vendethiel- | it's basically a BEGIN | ||
| masak | with a return value, yes | ||
| except you can use it later, too, at runtime | |||
| what's the discrepancy here? I wanted something like "the thing that can statically evaluate 'safe' values, kind of like for constant folding", but I ended up with a full-blown eval() | 12:50 | ||
| to a first approximation, it should refuse to evaluate function calls | |||
| vendethiel- | .oO( ... and now I have two problms ) |
||
| masak | yep :) | 12:51 | |
| it feels unfair to allow operators but to disallow function calls | |||
| vendethiel- | i'm not sure it's a good idea to allow operators, even... | ||
| ..depends | |||
| masak | aye | ||
| vendethiel- | maybe foo(BEGIN 3 + 4) works? | ||
| means you explicitly tell it to | |||
| the difference between getting the AST and the value, at another stage | 12:52 | ||
| masak | the reason constant-folding works on operators is that it's guaranteed that those operators are free of certain bad things like side effects | ||
| maybe we need to somehow whitelist the built-in operators (and possibly some safe functions too, like abs()) | |||
| by the way, I'm toying with the idea that an identifier in 007 shouldn't have a string as data, but a declaration, a Q node somewhere | 12:53 | ||
| I'm unsure enough about the idea to want to try it in a branch to see how it pans out | |||
| but the notion of "where was this identifier declared" is a pretty central one, and that's what we keep doing with those strings anyway | 12:54 | ||
| damn, I feel silly for not noticing before that handling expressions means handling function calls :) | 12:56 | ||
| vendethiel- | well | 12:58 | |
| when I think about it... | |||
| masak | ...when you think about it, you're at a loss for words...? :P | 13:04 | |
| github.com/masak/007/commit/e98bda...5a2c485347 :) | 13:12 | ||
| vendethiel- | no, I think it's cool | 13:28 | |
| we are able to run function calls at BEGIN time | |||
| masak | I'm not worried that it doesn't work | ||
| I'm more worried that I accidentally introduced the full power of eval() into a construct that I intended to be much more limited | 13:29 | ||
| s/that I/because I/ | |||
| vendethiel- | yeah | 13:36 | |
| but to be honest | 13:43 | ||
| a macro *is* such an eval construct | |||
| masak | mmh? | 14:35 | |
| if it were, we wouldn't need melt() | |||
| vendethiel- | well, it doesn't happen at the same time | 14:41 | |
| it's not on the same level | |||
| masak | right | 14:48 | |
| that's what strangelyconsistent.org/blog/macros...el-is-hard was about :) | |||
| vendethiel- | right. | 14:50 | |
|
15:16
FROGGS joined
|
|||
| masak | FROGGS: hi, good thing you're here! :D | 16:11 | |
| irclog.perlgeek.de/6macros/2015-11-28#i_11616987 | 16:12 | ||
| vendethiel++ pointed out that github.com/masak/007/issues/88 is preventing it from working right now | |||
| but it's close. very close! | |||
| vendethiel-: umm. injecting a declaration is basically "adding it to the program", so it makes sense that a thing is declared thereby. | 16:24 | ||
| vendethiel-: but what happens if you remove a Q::Statement::My from an existing program? | |||
| (at compile time) | |||
| vendethiel- | wut? | 16:25 | |
| you mean in a visitor macro? | 16:26 | ||
| masak | yeah | 16:31 | |
| thinking about it, I can see solutions, but it feels like a classical case of "disallowed pending a convincing use case" | |||
| basically, you'd run into trouble if the declaration had any downstream consumers | 16:32 | ||
| same deal with, say, renaming a declaration -- or changing it in various other ways | |||
| it feels like it fundamentally breaks the lexical model. adding declarations is fine, but changing or removing declarations that may have been used is asking for trouble | 16:33 | ||
| vendethiel- | mmmh | ||
| yeah | |||
| masak | (note that I'm all for mutating/removing other types of statements) | 16:41 | |
| and presumably removing a whole lexical block is fine, even though it contains declarations, etc | |||
| in some sense, it feels like -- if you're going to remove the declaration of something you don't want used later, you might as well make a visitor macro that taboos any usage of that declared thing. and we might as well encourage you to do that, since it's saner. | 16:45 | ||
| FROGGS | masak: \\o/ | 16:54 | |
| masak | \\o/ | 17:03 | |
| 007 is racing past Rakudo in capabilities pretty quickly at this point | 17:04 | ||
| we've laid the groundwork well | |||
|
19:44
vendethiel joined
|
|||
| vendethiel | so, what's the difference between | 21:30 | |
| sub foo...; foo; | |||
| sorry | |||
| macro foo; foo; | |||
| VS | |||
| sub foo...; BEGIN melt foo; | 21:31 | ||
| er, well, I guess `melt BEGIN foo` | |||
| masak | melt is for expressions. macros are for all kinds of things! | 21:42 | |
| the only thing that currently limits macros to mostly expressions is our inability (so far) to break out of the "macros are function calls or ops" mold | 21:44 | ||
| but the other two types are a step towards breaking out of that mold | 21:45 | ||
| hm, maybe we should make the Val::None slots in the Qtree explicit in the lispy AST format | 22:12 | ||
| instead of just, as now, omitting them | |||
| though we can't use 'none', because (sensibly) that's a Q::Literal::None | 22:13 | ||