This works:
julia> :( x + y )
:(x + y)
I'd like to interpolate an operator instead of having a hard-coded +
. I can do this:
julia> op = :+
:+
julia> :( $op(x, y) )
:(x + y)
Is there a way to keep the x op y
syntax? This fails:
:( x $op y )
ERROR: syntax: missing comma or ) in argument list
I doubt it. If it's not syntactically okay it's hard to get further. Of course you can do string interpolation and Meta.parse
but you probably don't want that.
Thanks! Yes, I thought of Meta.parse
, but basically I was just wondering if I was missing something. The manual doesn't provide clarity about this.
I'm not sure why it fails, though. My mental model (which is likely wrong) is that :( x $op y )
is first converted to :( x + y )
; that is, interpolation happens before further parsing of the quote. Probably parsing occurs before interpolation.
It would be kinda hard to interpolate before parsing. E.g. making sense of
julia> op = [:+, :-]
2-element Vector{Symbol}:
:+
:-
julia> :($(op[2])(x, y))
:(x - y)
Couldn't it do :( $(op[2])(x, y) ) -> :( -(x, y) ) -> :( x - y )
? Interpolate first, then parse.
the latter two are the same though, from the parsers' POV
the trouble is that :( x $y z)
could, depending on y
, be :( -(x,z) )
or :( x g z )
, which would be a syntax error
so you _have_ to parse & evaluate y
before you're done parsing the outer expression, just to decide if the outer expression is valid
How would it know the meaning of (op[2])
before parsing?
it doesn't, but as $(op[2])
is a complete expression already, it is free to parse & evaluate that in isolation
I see as similar to string interpolation: just blinldy replace tokens inside the quote (that is, replace $(op[2])
with :-
), then parse the resulting quote. If it is invalid, throw a syntax error, but not before.
@Sukera I don't know what you mean by "in isolation". In both :( $op(x,y) )
and in :( x $op y )
, $op
has the same value and should be parsed and evaluated identically?
Clearly it is not just a parsing problem:
julia> op = :+
:+
julia> Meta.parse("x $op y")
:(x + y)
well.. that's because :()
is not actually an Expr
literal?
so it's not quite doing the same as what you're writing with Meta.parse
what parse
gets is already "x + y"
- there's never an expression interpolation going on
:( ... )
is a QuoteNode
literal, which returns whatever expression is enclosed in the brackets
Right.
so at that point, you run into a conundrum - do you lower first, or do you interpolate first?
when parsing the inner expression, that is
logically, interpolation happens after lowering, because only then will the overall structure no longer change - you take a finished & lowered expression and splice it into another lowered expression tree
what you're proposing is doing that before the outer expression tree is done lowering, to change how the final tree looks
Well, not proposing, just trying to understand :sweat_smile:
:)
suppose you allow that - I think you'd quickly get very unlucky with interpolation performance, because then you'd have to potentially rebalance/relower the expression tree after every interpolation, which could get oh so very expensive with macros
in essence, they're doing the same interpolation thing, just with different surface level syntax & a slightly different step in the pipeline, I think
The way I interpret what you're saying (and this is probably what Gunnar also meant) is that the parser doesn't know what to do with what is essentially :( token1 token2 token3 )
, because it doesn't know (yet) that token2
is an operator (or function in general).
Whereas in :( token1 operator token3 )
and :( token2(token1, token3 )
, it's clear which items are functions. Is that right?
yeah, should serve well enough as a mental model
except for the first one, you can take a look at the difference with Meta.@dump
though in this case, you won't see one with +
because they parse to the same thing since they're both valid and the first one won't parse at all, because it's not julia code
either way, it depends on what token2
_is_ to work, and since only infix operator literals (or non-complex literal interpolations) are allowed there, if the parser (waaaay before lowering or the concept of a "function" is a thing) can't tell, you can't do it
mbaz has marked this topic as resolved.
Last updated: Nov 06 2024 at 04:40 UTC