|
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. |
|||
|
00:17
Ven_ joined
01:21
Ven_ joined
03:35
Ven_ joined
04:36
Ven_ joined
05:38
Ven_ joined
05:41
vendethiel joined
06:48
Ven_ joined
08:36
pdcawley joined
|
|||
| pdcawley | Morning _Ven | 08:38 | |
|
09:51
Ven_ joined
|
|||
| Ven_ | ahoy | 09:59 | |
| did I link eslisp here already? | 11:10 | ||
| yes I did | |||
| pdcawley | _Ven: If we don't have an explicit quote form, doesn't that make (the relative common) elisp pattern of: `(func-name (quote ,symbol) ,@args) a wee bit tricky to manage? | 11:30 | |
| Ven_ | we don't use symbols for names | 11:31 | |
| barring the hygiene problem for now: | |||
| quasi { sub {{{$name @ Q::Identifier}}}({{{@args :: Q::ArgList}}}) {} } | |||
| pdcawley | So, how do you arrange to expand a macro into a function call which accepts an expression in quoted form as its argument? | 11:32 | |
| Ven_: That sets the type of the unquoted thing? | 11:33 | ||
| Ven_ | supposedly, yes :) | ||
| quasi is quote, {{{ }}} is unquote | 11:34 | ||
| pdcawley | And 'quasi { ... quasi { {{{ when_is_this_unquoted }}} }'? | ||
| Pretend I balanced up the } at the end correctly. | 11:35 | ||
| Ven_ | the unquote-time is something masak blogged about already | 11:36 | |
| I can't remember the name he used | |||
| but he seems he wants them macro-late-bound (i.e. replaced when the quasi "escapes" the macro iirc) | |||
| pdcawley | I'm not sure I get where he's going with that tbh. | 11:37 | |
| macro expansions and quasi expansions surely all happen at parse time. | |||
| macro ...: turns ... into (say) a quasi quote which can only 'see' the scope of the macro body that generated it, macro returns a fully expanded syntax tree at that point, and the parser continues on its way. | 11:39 | ||
| If you need to capture something for use at runtime, you do it through the standard mechanisms of closures, etc. | |||
| things get icky if you don't have a way to introduce 'anonymous' identifiers that aren't going to accidentally shadow anything in the containing scopes. | 11:41 | ||
| Ven_ agrees ;) | |||
| macros are hygienic in 007, afaik | |||
| so no gensym problems | |||
| pdcawley | if you can't do macro foo($expr) { $memo = gensym; quasi { my {{{$memo}}} = {{{$expr}}}; ... } } | 11:43 | |
| then you're in for a world of pain. | |||
| And if you insist on hygienic macros, you're going to have to understand far more about Scheme's hygienic macro systems than I could ever be bothered to do. | |||
| How implemented are macros? | 11:45 | ||
| Ven_ | dunno | 11:52 | |
| also, just like I said, `my $memo` inside the quasi would work fine right now | |||
| because macro have a specific lexpad (Perl 6 talks about a COMPILING namespace as well) | |||
| there are always way to work "around" hygiene if you need to. it's not like you can't write anaphoric macros in scheme | 11:53 | ||
| racket offers a few more ways around (syntax parameters, etc) | |||
| pdcawley | Ven_: problem I have with the various 'ways around' is that the basic kit of parts ends up being more complicated in cases where you might not want them to be. | 12:02 | |
| Explicit gensym can be a little like juggling hand grenades, but it has the great advantage of the language not deciding for you what the Right Way is. | 12:03 | ||
| Ven_ | sure | 12:04 | |
| but sometimes, it's good the language takes a safer default | |||
| and gives you enough tool to disable that default where needed | 12:05 | ||
| i.e. racket's format-id (in racket/syntax) | |||
| which I used, say, github.com/vendethiel/brain.rkt/bl...rs.rkt#L35 | |||
| masak | re hygiene -- you should be able to do COMPILING::{{{$name @ Q::Identifier}}} | 12:10 | |
| pdcawley needs to go and read up on this, methinks. | 12:11 | ||
| Hmm... consider: macro foo ($expr) { quasi { { my $bibble = '22'; {{{ $expr }}} } } | 12:16 | ||
| camelia just fell over in a heap when I did 'quasi { $bibble }.PERL.say' because it couldn't see a declared $bibble. Thought (one of) the point(s) of quasi was to just make an AST without worrying to much about scoping rules. | 12:17 | ||
| masak | who told you that? :) | 12:20 | |
| pdcawley | Every other language that has quasiquoting. | 12:23 | |
| Quoted form is entirely unattached to a scope, unquoting within the quasi happens in the containing environment, but the quoted form doesn't have a scope attached until it's plumbed back into some evaluable context. | 12:24 | ||
| masak | maybe this discussion will be easier if we both start from what's in S06...? | ||
| I mean, much of it is superseded or obviated by things I've discovered lately, but the hygiene and scoping is pretty much in there and pretty clear. | 12:25 | ||
| pdcawley | masak: can I write (say, and I know that perl6 has builtin ways of doing this, but bear with me) a macro like: anaphoric-map { $it * 2 } @args; where the 'anaphoric-map' expands to: map -> $it { $it * 2 } @args, or map -> $it { $expanded_expression_involving_it } @args? Because if that's not possible without tapdancing on the calling side of things, that rules out a whole class of useful macros. | 12:29 | |
| masak | yes, I know. I've had basically the same discussion with Ven. | 12:30 | |
| I... I don't know yet. | |||
| the way things parse in Perl 6, you'd have to at least intercept the macro before it gets to that block and sees $it | 12:31 | ||
| it's possible 'is parsed' might help with that, but I don't feel things have clicked with 'is parsed' quite yet. | 12:33 | ||
| pdcawley | masak: Point is, if you spot a macro during parse, then all bets are off as to the environment of the rest of the parse. Have to wait 'til the macro grabs the expressions it needs (parsed in a 'lax' environment, allowing undeclared variables to get through) and returns an AST, only then can you turn stricture back on. | ||
| masak | we've had to give up and do that in quasis already. | 12:34 | |
| because quasis can contain unquotes, and you can't apply the macro anyway until the unquotes are "filled". | |||
| pdcawley | parsing the 'arguments' to macros as if their scope is already known is a recipe for failure. | 12:35 | |
| you mean i'm going to have to quasi quote macro _arguments_? That's insane. | |||
| masak | no, that doesn't make sense. that's a category error. | 12:37 | |
| pdcawley | Okay. Misunderstood you then. | ||
| masak | I'm sure we can work things out little by little :) | 12:38 | |
| I am eager to bring macros to Perl 6 in a way that makes sense. this means listening to Lisp advice, but also not heeding it without understanding the consequences, and the different forces that apply to the Perl 6 design. | 12:40 | ||
| pdcawley | Hmm... just thought... say you have a noddy macro that takes an expression that contains a variable name as an argument. When you do: quasi { {{{$arg}}} }, then the name in $arg is out of scope when the quasi is built. No different from quasi { $out_of_scope_var }, so rakudo as she stands is going to barf horribly at that point. | 12:41 | |
|
12:41
Ven_ joined
|
|||
| masak | pdcawley: currently the rule is this: quasi blocks respect lexical scoping. synthetic Qtrees (created using .new on Q types) don't have any such limitations. | 12:42 | |
| you can also "detach" a quasi or macro argument from its scope by calling .detach on it | |||
| but of course, by the it might be far too late, if you already got a parse error | 12:43 | ||
| pdcawley | That seems arse about face. | ||
| masak | so maybe what Ven++ said makes sense, and it should also be an adverb... | ||
| pdcawley | Once a quasi has finished unquoting its contexts, it should be entirely detached. | ||
| until it's plumbed back into the ast at the macro call site. | 12:44 | ||
| masak | but the unquoting doesn't happen until sometime in the middle of the macro call, quite a bit later than the unquote is parsed | 12:45 | |
| still at compile time, but later during the compile | |||
| Ven_ | irclog.perlgeek.de/6macros/2015-11-03#i_11474298 | ||
| pdcawley | masak: No. | ||
| Ven_ | I talked about racket's syntax parameters for that, and a few other solutions | ||
| pdcawley | Unquoting happens within the scope of the macro call. Macro returns a clean AST. | ||
| Surely. | |||
| Ven_ | > at least intercept the macro before it gets to that block and sees $it | 12:46 | |
| masak | both of you seem to have pretty wild disagreements with actual Perl 6 spec of how Perl 6 macros should work... | ||
| pdcawley | Since the actual perl 6 spec specifies that Perl 6 macros do impossible things (like be callable at runtime unshielded by an EVAL), then I'm taking it with a serious pinch of salt. | 12:47 | |
| masak | I may be able to afford such disagreements, but only if I happen to stumble over a *fully-formed* proposal of how it *should* work within the bounds of Perl 6. | ||
| yes, please feel free to take it with a pinch of salt. I do. | |||
| but it's pretty clear on the lexical scoping. | |||
| and I haven't really seen a better proposal, only Lisp-inspired dreaming. | |||
| pdcawley | masak: I'm going by the idea that a macro returns a 'syntax tree that needs no further parsing'. Since parsing seems to be intimately tied in with scoping, I'm really not sure how that's possible. | 12:48 | |
| masak | ok, let's make this very concrete | ||
| github.com/masak/007/blob/master/t....t#L46-L59 | 12:49 | ||
| as of yesterday, that test there passes | |||
| pdcawley | masak: That should be a bug. | ||
| Only way you should be able to get at x is through an unquote. | 12:50 | ||
| quasi { say({{{x}}}) } | |||
| masak | in Perl 6, macros have hygiene. | ||
| if you don't want the hygiene, use COMPILING:: | 12:51 | ||
| pdcawley | macro foo(varname) { return quasi { say({{{varname}}}) } } <- how is that different? | 12:52 | |
| Ven_ | pdcawley: yeah, I argued the same | 12:53 | |
| pdcawley: : because varname is an AST there | |||
| pdcawley | You're just complicating things horrifically. | ||
| Ven_ | not a value | ||
| but I agree "x" shouldn't work. that's not the right time. | |||
| masak | I'm sorry, but you're both tilting at windmills at this point | 12:54 | |
| Ven_ | "x" works there because it's just a value. {{{ }}} is not about the evaluation time, it's about interpreting its content as an AST | ||
| masak | because I *do* understand how that works. I've implemented it. twice. | ||
| Ven_ | oh, I know how that works. I just explained it | 12:55 | |
| masak | oh, good. | ||
| yes, and I think I agree with your explanation. | |||
| in the way "x" works there, the quasi is basically just a normal block. | 12:56 | ||
| pdcawley shudders | |||
| masak | duly noted. next topic? :) | 12:57 | |
| pdcawley | So... if I know (or hope) there's an x in the outer scope, I do quasi { COMPILING::x }? | ||
| masak | right | ||
| and *that* one gets late-bound and checked at insertion, like you want | |||
| pdcawley | And, say I have my $foo = 10; macrocall $foo; and I want that to expand to: 'my $foo = 10; do { my $foo = $foo + 1; say $foo }', how do I write the quasi. | 13:00 | |
| Ven_ | masak: so, my example in #perl6, is it working in 007? | ||
| pdcawley | afk: lunch | 13:01 | |
| Ven_: Hadn't even thought about state... | |||
| Ven_ | well, I did, so I'm concerned ;-) | 13:02 | |
| masak | Ven_: 007 doesn't really have state. | 13:06 | |
| pdcawley | back | 13:59 | |
| Just a thought, the problem I'm having grokking quasi as it stands in perl 6 is that it isn't really quasiquote. | 14:00 | ||
| If you were to make it so that everything in a quasi block had to be explicitly unquoted, named in full or actually declared within the quasi I'd be less bemused by it. | 14:01 | ||
| The magic interpolation of variables without explicit unquoting seriously fucks with my head. | |||
| So, the test that masak posted should be a syntax error (because x is neither declared in the block nor fully qualified). I'd expect {{{ $not_an_expr }}} to be equivalent to {{{ $not_an_expr.perl.AST }}} or whatever the magic is. | 14:04 | ||
| masak | since I've already been over most of this with Ven, I have a comment from an issue ready: github.com/masak/007/issues/63#iss...-152511022 | 14:06 | |
| if you could give your thoughts on that comment, I'd much appreciate it | 14:07 | ||
| pdcawley | If you're not returning a fully resolved AST from the macro, you're going to be making a rod for your own back. | 14:12 | |
| masak | let's come at this from another angle | ||
| in Perl 6, parsing is very much intertwined with symbol lookup | |||
| pdcawley | Then that basically makes macros impossible. | ||
| masak | please listen for a bit | ||
| pdcawley | masak: Just looking at your 'return'. | ||
| masak | is `foo bar;` a valid expression or a syntax error? it's the former if `foo` is a function. it's the latter if `foo` is a type. | ||
| pdcawley | and you can't know if foo is a macro. | ||
| Because you don't know, ahead of time, what the macro will expand to. | |||
| masak | that's why macros expand ASAP | ||
| I feel we are discussing at almost complete cross purposes | |||
| pdcawley | masak: Yes, but you then have to run a full check on the AST they return. | ||
| def macro foo { quasi { return 42 } }; foo; should first of all expand to 'return 42' and then trigger the 'this isn't legal code' warning. | |||
| It certainly shouldn't short circuit the return from the macro, which is what you seem to be saying on issue #63. | 14:13 | ||
| masak | `return` binds lexically to the surrounding routine. | ||
| pdcawley | Not if it's quoted it doesn't. | ||
| masak | which happens to be a macro. | ||
| Ven_ won't argue again over this | 14:14 | ||
| masak | pdcawley: you're describing some other language currently. | ||
| pdcawley | quoting: DO NOT EVAL THIS YET | ||
| spec for quasi as it stands is batshit insane. | |||
| if quasi isn't quoting, don't call it quasi because you will break everyone who comes to Perl 6 from every other language that has quasiquoting ever. | |||
| And you'll be dealing with them going WTF!? all the time. | 14:15 | ||
| And, if you do want quasi { return } to return from the macro, how am I supposed to return a quasi that will return from the _calling_ scope? | |||
| ie, where's the real 'quote'? | 14:16 | ||
| the one that says "do not eval this yet until it's either been plumbed into a bit of AST that will get evaulated, or is explicitly evaluated in a given environment"? | 14:17 | ||
| Because if that version of quote doesn't exist, there will be classes of macros that it's impossible to write. | |||
| One of the things that one might want to do within a macro is to change the semantics of 'return', after all. | 14:18 | ||
| Ven_ | different kind of macro | 14:19 | |
| let's not mix things up | |||
| masak | COMPILING::return | ||
| Ven_ | renaming "quasi" is the topic right now, not codewalking | ||
| masak | perhaps | ||
| I agree `quasi` could be better named | 14:20 | ||
| pdcawley | As soon as you see a macro in the stream of code, you have to treat all the parsing the parser does as tentative and liable to be thrown away. The only AST that's actually checkable in a meaningful fashion is the AST that's returned from your macro. | ||
| masak | I've been thinking of simply calling it `quote { ... }`, like Julia does | ||
| pdcawley | masak: special forms are namespaced? | ||
| Ven_ | that's in lisp macros, pdcawley, not in perl6's | ||
| pdcawley | masak: Don't do that, it's not a quote either. | ||
| Ven_ | in perl6, quasis have a lexpad. | ||
| masak | and then maybe renaming `{{{ }}}` to `unquote( )` | ||
| pdcawley | Ven_: So I gather. I still don't quite get what Perl6 gains from this. | 14:21 | |
| masak | (a) it's symmetric, (b) it gets rid of the triple braces which everybody seems to love to hate | ||
| Ven_ | {{{ }}} vs unquote is probably the smallest of concerns :) | ||
| pdcawley | Ven_: Seems to me that you've got something that complicates implementation and limits the capabilities of the macro system at the same time. | ||
| masak | I'm going to bed. will let you two arrive at the perfect synthesis in the meantime. will backlog later. | 14:22 | |
| 'night | |||
| Ven_ | pdcawley: I'm not arguing in favor of either here | ||
| 'night, masak | |||
| pdcawley | I don't understand how quasi seems to be trying to be something that makes an AST but which can be returned from to a weird place. Don't like the idea of having to sprinkle 'COMPILING::' all over the shot to get control structures to work right - seems to go very much against the Huffman idea... | 14:26 | |
| Ven_ | pdcawley: I'd also agree quasi{} shouldn't do that, but we've established that the current quasi{} isn't a quasi | ||
| well, only `return` has such an effect, AFAIK | 14:27 | ||
| pdcawley | Ven_: When are you _ever_ going to want quasi { return ... } to return to the place where the quasi was built? | ||
| Ven_ | ask masak, I argued against this as well. I just think it's for consistency's sake with how "hygiene" works | 14:28 | |
| pdcawley | quasi is _not_ an execution context in the way that other blocks are. | ||
| Ven_ | (I argued that hygiene should not extend to return) | ||
| pdcawley | quasis having lexpads are the problem if you ask me. | 14:29 | |
| Make the rule every variable used in a quasi should be either: fully qualified, declared within the quasi, or explicitly unquoted and the quasi itself doesn't need a lexpad. | 14:30 | ||
| By the closing '}' of the quasi, everthing in it should be resolved. | |||
| Ven_ | quasi should be called "delayed-ast" or something :P | ||
| you're arguing for lisp macros | 14:31 | ||
| pdcawley | Then when it's patched into the final AST, it acquires an appropriate lexpad and gets checked to make sure everything's in scope. | ||
| Ven_: No, I'm arguing for a useable quasi. | |||
| Can implement hygenic or unhygenic macros on top of such a quasi, it's orthogonal. | 14:32 | ||
| Ven_ nods | |||
| pdcawley | The problem (as I see it) is the implicit unquoting of my $x = 4; quasi { $x } | 14:33 | |
| Macros are hard enough without having to worry about implicit behaviour. | |||
| Ven_ | it's not unquoting, again | 14:35 | |
| forget about the "quasi" name | |||
| it's not quoting | |||
| so it's not unquoting | |||
| {{{ }}} is just splicing | |||
| pdcawley | Then I really don't see the point of it. | ||
| Because I will bet real money that there _will_ be a need for lisp style quasiquoting, and if you can't implement that in Perl 6 there's a problem. I | 14:37 | ||
| I'd expect whatever perl6 provides to have a superset of lisp quasiquoting semantics, not some spavined version of it that doesn't seem to have semantics like anything else ever. | 14:38 | ||
| But apart from that, it's awesome :) | 14:39 | ||
| Ven_ | well, at least we agree on that :P. | 14:41 | |
| fwiw, I'm very much used to Lisp macros, so I agree with your points in a lot of ways. Whatever is we're getting, we should not be pretending it's "lisp-style" | |||
| 'cept for the fact it's acting on a AST level, but.. | 14:42 | ||
| pdcawley | Given a lispy quasiquote and codewalking, I could implement quasi. However, given quasi and code walking, I'm buggered if I can see how to implement a lispy quasiquote. | 14:55 | |
| Which says to me that quasi is underpowered. | |||
| or that my imagination isn't up to the job (entirely possible) | |||
| Ven_ | you'd implement perl6's quasi? means you need to walk on all the `let`, then all the quotes, and replace them there | ||
| actually, only the quotes you know will be used as an AST. | |||
| which is different in the non-homoiconic perl6 :) | |||
| pdcawley | Also, if whatever we end up with isn't capable of implementing analogues with pretty much everything in Let Over Lambda, then it's underpowered. | ||
| Ven_: Where else is quasi used? | |||
| Ven_ | no, the opposite | ||
| quote is used for many things in lisp. in perl 6, quasi{} is only for an AST | |||
| pdcawley | Okay... perl6ish quote? | ||
| Ven_ | yeah. | ||
| "late-ast" | |||
| not "quasi" :) | |||
| pdcawley | To implement quasi, given lispy quasiquote, don't you just write macro quasi($block_expr) { walk the tree looking for unqualified references to variables that are only available in the COMPILING scope and haven't been declared within the quasi block and replace them with {{{ $var.perl.AST }}} } | ||
| Ven_ | then you need to pass all the bindings you currently have declared to quasi{} | ||
| there's no "bindings"(ruby-like) in CL :P. | |||
| (there are pseudo packages, like MY, in 6) | |||
| pdcawley | can't the macro see COMPILING:: ? | ||
| Ven_ | wrong one. COMPILING is the one "down there", not the macro invoking quasi | ||
| there's OUTER::, probably | 14:56 | ||
| maybe. | |||
| pdcawley | Ven_: But when quasi gets invoked within a macro, surely the COMPILING:: is the invoking macro's scope. | 14:57 | |
| Jesus wept, but hygiene is a horrific can of worms. | |||
| Ven_ | yeah, you're probably right | 14:58 | |
| *g* | |||
| pdcawley | Ven_: About what? COMPILING, or hygiene being a can of worms? | ||
| Ven_ | COMPILING. | ||
| I like hygiene as demonstrated in scheme/racket | |||
| though let over lambda has example of a defmacro!g that helps plainly with hygiene | 14:59 | ||
| pdcawley | Ven_: Yeah, but it's a can of worms for the implementers. | ||
| Ven_ | (and defmacro!o for once-only-evaluated stuff) | ||
| pdcawley | Yeah, defmacro! and friends in LoL are awesome. | ||
| Ven_ nods | |||
| pdcawley | Easy to write hygienically, but all the icky power of unhygenic macros when you need it. | 15:00 | |
| Ven_ | I have all of that in racket and scheme as well, though :) | 15:01 | |
| but yes. | |||
| a bit too ad-hoc for perl6 | |||
| pdcawley | ISTM that scheme/racket hygiene is relatively easy to implement when your AST is so trivially walkable and easy to pattern match against as scheme's is. | ||
| But trivially walkable and easy to pattern match against aren't things I associate with Perl. | 15:02 | ||
| Personally, I'd advocate for the approach of implementing an ad hoc unhygenic system first, then using that to experiment with hygenic mechanisms. Would help drive quality AST walking tools to be implemented too, which will be useful for more than just macro writers, then pick the hygenic scheme that works and enables everything that the unhygenic system did, then rip out the unhygenic stuff, write a library that implements it on top of | 15:05 | ||
| the hygenic scheme for those that don't want to have to rethink their libraries and are prepared to pay the performance hit. | |||
| Ven_ | meh, performance | 15:13 | |
| there's also the notion of templates, which are pretty different | |||
| but as always, implementable on top of macros :) | |||
| pdcawley | Point being take the Perl 5 approach: implement a minimal kit of parts, use that kit to develop the Right Thing, then make the Right Thing what Perl does. | 15:47 | |
| Don't decide early. | 15:48 | ||
|
19:23
vendethiel joined
|
|||
| vendethiel | github.com/densh/scala-offheap/blo...cate.scala macros gone wrong :P | 22:12 | |
| that's what you get for being unable to generate macros from macros | 22:13 | ||