masak | Ven: ok -- for some reason that's what I expected you to say | 07:30 | |
Ven: I mean, it is a re-packaging of the idea of "watcher macros", so I basically already got your reaction once | |||
Ven: I dunno, I'm not betting on the idea being viable or anything. but it does feel like it solves a bunch of related use cases | 07:31 | ||
two or three are linked from #349, but maybe it's only clear in my head how it'd work :) | |||
I *definitely* prefer the `is context` trait to all the strange ideas I had about an `inside` block | 07:32 | ||
Ven: I wrote out a concrete example for you with & and | in #349 | 08:36 | ||
11:22
Ven`` joined
|
|||
Ven`` | masak: I certainly find it saner than watch macros :) | 11:33 | |
masak | good :) that's all I could hope for | 11:40 | |
Ven`` | feels like it's missing some parentheses to me, in the examples, btw | ||
masak | why? `==` is tighter than `&&` and `||` | 11:41 | |
Ven`` | what guarantees context.root.op is ==? | ||
ah, in this case it doesn't matter | |||
masak | the `is context` | ||
it only captures a root of that prec level | |||
note that the macros also hinge on a (not yet in 007) distinction between *ops* and *op applications*, which I think you'll like | 11:42 | ||
Ven`` | I don't understand how that works in practice | ||
when/how is opLhs set? | 11:45 | ||
also, you use context.root.op but the key is called "level", hence why I got confused I think | |||
masak | the macro triggers when the context root has finished parsing -- that is, when the `==` and its rhs/lhs are all parsed | 11:46 | |
perhaps realistically the macro will trigger somewhat later, when the whole expression has finished parsing | |||
Ven`` | ah so it's not so much saner than watch macros | 11:48 | |
masak | haha | ||
...no, guess not | |||
it's still done with two "players" -- the deeper macro and the shallowed context root | |||
Ven`` | I still feel uneasy about inside-out macros | 11:50 | |
11:55
Ven`` left
|
|||
masak | is there some way to express those reservations, aside from the emotional aspect? (which I get, kinda) | 11:55 | |
11:55
Ven`` joined
|
|||
masak | 1 backlog | 11:56 | |
Ven`` | damn it, train | ||
well, I think I explained better than the text yesterday. I thought the idea was more akin to... help build DSL, like we talked about a long time ago, by declaring that some macro can only exist in the context of another (we used transaction/commit as an example). I think I mixed both. | 11:57 | ||
Inside-out macros make me uneasy because this is the opposite order of how it usually goes: a macro runs as soon as it itself is complete | |||
masak | agreed. | 11:58 | |
Ven`` | A macro that runs only when whatever contains it finishes parsing instead makes me feel very uneasy because I can think about many situations of when that could be problematic (but maybe it's not actually) | ||
masak | let's see if the following helps: | ||
Ven`` | for "contextual" macros, I don't like that it feels like declaring a global, I don't like that it feels like... something is "shared" between & and ^, when really, it's just using the same mechanism to trigger | ||
masak | (a) I expect a contextual macro should either *eventually* run when its context is parser, or *immediately* throw a parse error about being outside its context | 11:59 | |
Ven`` | that's why "(a & b) == c" makes me uneasy :) | ||
masak | (b) I expect a macro invocation that survives until runtime should throw an exception, because calling that macro at runtime doesn't do anything useful | ||
oh damn, `(a & b) == c`... | 12:00 | ||
yeah, my test implementation is definitely wrong :( | |||
it assumes the junction ops are on the rhs of the `==`, which is not at all guaranteed | 12:01 | ||
I blame lack of coffee | |||
or possibly too much coffee | |||
Ven`` | so, really, we have == that's actually a DSL | 12:02 | |
and is context is a tool to help build a DSL by adding "sublexical grammar" to it | |||
masak | that's one way of putting it, yes | ||
but it's not so much a DSL that it brings a completely new evaluation semantics to `==` | 12:03 | ||
just an augmented one | |||
Ven`` | my only point with that was, that it's really pretending == is a macro, that treewalks to find ^, & and rewrite itself if they are found | ||
the idea of composability is certainly an interesting one | 12:04 | ||
macros aren't usually composable, er, augmentable like the point you're making here | 12:05 | ||
(well, here it isn't a macro that's augmented, but...) | 12:06 | ||
masak | github.com/masak/007/issues/349#is...-409551778 | ||
the .cloneAndSubstitute thing seems like a common thread through all the use cases | 12:07 | ||
maybe a better name is called for -- .template, perhaps? | |||
it's kind of the opposite of a quasi block in a way, in that you're not interested in specifying all the unchanging bits, you just want to find an unquote slot to stick your varying part in | 12:08 | ||
Ven`` | the way I see it, in a current lisp-ish macro-ish way, would be to define `==` as a template where you look for & and ^, like I wrote earlier | 12:09 | |
which might be template-ish | |||
in the scheme/racket/nim template sense | |||
"syntax rules" | |||
masak | aye | 12:10 | |
I'll just say for now that I'd like to understand template rules a bit better | |||
and Racket in general, I guess | |||
Ven`` | I'd like a bit more info on cloneAndSubstitute ;) | 12:11 | |
masak | it's basically the logical conclusion of what I'm trying to do here: github.com/masak/007/issues/158#is...-304233756 | 12:34 | |
Ven`` | how very inside-out of you | 12:44 | |
let me re-read that one! | |||
masak | well, the `inside` idea is a dead end | ||
the important bit is the line with `return statement_ast.clone().find(...).replace(expr_ast);` | |||
it feels to me that's a recurring pattern with these contextual macros | 12:45 | ||
"in the grander context, I'd like to be replaced with..." | |||
Ven`` | I enjoy the jquery analogy | ||
masak | yup | 12:46 | |
12:53
Ven`` left
12:57
Ven`` joined
|
|||
Ven`` | ok, so: | 12:58 | |
$("infix:<==>").on("infix:<&>", sub (lhs, rhs, eqOp) { ... }) | 12:59 | ||
masak | yeah, something like that | 13:05 | |
Ven`` | bind(&infix:<==>, sub infix:<&>(lhs, rhs, context/* this argument added by the bind macro */) { | 13:06 | |
context.replaceWith(...); | |||
}); | |||
we can look at such a high-level API first, for sure | 13:07 | ||
masak nods vaguely | |||
Ven`` | my first gut feeling is that the sub should return a new AST for the toplevel (infix:<==>) one, not for a infix:<&> (otherwise just write macro infix:<&>) | ||
I kind of want to talk to cog++ about this, too, this feels reminescent of a project he worked on | 13:08 | ||
masak | agree about the gut feeling | 13:10 | |
actually my first instinct was that context macros wouldn't return new ASTs but rather mutate the ASTs it was given, but... with something like .cloneAndSubstitute it looks like returning might be enough | |||
Ven`` | I don't believe in mutating ASTs :P | 13:11 | |
feels wayyy too scary | |||
masak | I can only agree fully | ||
Ven`` | I know of some "simple" langs that did, one in particular called OOC, and it was hell | 13:12 | |
masak | it's not that I *don't* want to do scary things, but rather that sometimes I don't spot the simpler option right away | ||
if I wanted to avoid scary things, I wouldn't have developed a macro-friendly language in the first place :P | |||
Ven`` | macro-"friendly", huh. As if not to scare them away :P | 13:13 | |
masak | heeeere, macro macro | ||
13:57
AlexDaniel` left,
AlexDaniel` joined
14:50
Ven`` left
22:43
Ven`` joined,
Ven`` left
|