Open ExpandingMan opened 7 years ago
I'm pretty sure I remember this being brought up before and people thought it was a good idea. I also know there's been talk of "finalizing" our AST/Expr representation for 1.0 as well.
This would largely rely on changing the AST representation to a more type-based one, where instead of using Expr
everywhere with different values for the .head
field, we use different types to represent different syntax nodes with specific structures. This would be a fairly disruptive change, but if we're going to do it, before 1.0 is certainly the time to do so. Now that macros can do dispatch (it's real dispatch, btw, just on ASTs), it would also allow writing some transformations more concisely and conveniently.
Going further, there could even be fully typed trees, like:
ForExpr.iterator IfExpr.condition
Going further, there could even be fully typed trees, like:
ForExpr.iterator IfExpr.condition
I would be very worried that that sort of thing would make symbolic manipulation too complicated. You'd have to remember or look up the fields for every possible type of expression. I think using head
and args
makes it pretty easy to infer what the structure of an expression will look like, it just gets really annoying sometimes to have to write big ugly conditional constructs to identify the head
s. (And it seems somehow "anti-Julian"!)
I can see how it might be an issue to iterate. Maybe a dict? IfExpr.args[:condition] for example
This is the kind of thing pattern matching is good for.
What I mean is that while dispatching on expression heads is somewhat useful, you need to be able to match on full tree structures to get any real benefit. Expression structures are also very flexible and dynamic, so they are not a great fit for the design assumptions of our multiple dispatch. This kind of programming really demands a feature that converts a series of tree patterns to a nest of if
statements. Such an approach also makes it easier to change the representation of expressions, since you only need to change the pattern compiler.
I've found #12102 which seems to be a suggestion that pattern matching for expressions be included in Base. The result seems to be that the poster wrote the MacroTools package which seems to still be actively maintained.
I find it interesting that most of the discussion in that post is about users not necessarily being knowledgeable about the AST. Personally, I find that to be a very small issue, I simply use the REPL to check what the head
s of various expressions are, and usually the args
are pretty obvious. Actually writing the macro code once I know exactly what I need to do is what I'm still finding slightly awkward.
It seems that this has now effectively been implemented through Val
, though this cannot directly be used in macro definitions.
Maybe I'm crazy but I could have sworn that at some point Val
was not working for Symbol
s. However, now it does. My original example becomes
h(::Union{Type{Val{:call}},Type{Val{:(=)}}}, expr) = f(expr)
h(::Type{Val{:block}}, expr) = g(expr)
macro m(expr)
h(expr.head, expr)
end
It's not beautiful, but it's certainly an improvement.
Is there some simple way of using Val
to allow macros declarations to behave as if they're dispatching on expression types?
Is there some simple way of using Val to allow macros declarations to behave as if they're dispatching on expression types?
Use a real pattern-matching library (like the previously mentioned MacroTools package)?
It would be really cool if one could do something like
which would be equivalent to
(of course we should think of a better name than
ExprHeadType
). Of course, this would have to then require that theexpr
argument be anExpr
rather than aSymbol
or literal. Any macros that aren't written withExprHeadType
would behave normally.Additionally, it would be nice to be able to dispatch functions on expression types (mainly for the purpose of helping macros), sort of like it's currently possible to do with specific values using
Val
. (I don't think that's a crazy extrapolation from current behavior, but I know very little about the compiler.)Is this completely crazy from a compiler perspective, or something people might be interested in?