& might be a bad choice for de-interpolation
it has different pred rule as $ so it is not very intuitive to use it sometimes
julia> ex = :(&A.B(a, b, c))
:(&(A.B(a, b, c)))
julia> ex.head
:&
julia> ex.args
1-element Vector{Any}:
:(A.B(a, b, c))
julia> ex = :(:($A.B(a, b, c)))
:($(Expr(:quote, :(($(Expr(:$, :A))).B(a, b, c)))))
this as a result caused us eval the entire call instead of the object in the following case
function Tree.print_node(io::IO, node::SpatialModulationType)
@match node begin
&SpatialModulationType.Global => print(io, "Global")
&SpatialModulationType.ScaledLocations(_) => print(io, "ScaledLocations")
end
end
& is still a nice and well-adopted symbol tho, though maybe we just need to find a way to fix the pred by matching more Julia expression patterns
Some information:
If we keep the concept of "stage"s in mind (e.g, compile time in CPP is stage 0 and the run time is stage 1), we can explain things cleaner:
$ means "splicing" which inserts into the next stage a value that is created at the current stage.
& means "pinning" which references a value in the current stage.
Julia already uses $ for "splicing", this notation is traditional. However, "&" for pinning is quite new (I only see this in Elixir if we don't consider the PL textbook/paper stuffs). Actually, almost all pattern matching programming languages decided to avoid pinning semantics because:
- pin operators can be confusing as
$exists - pin operators are difficult to optimize (MLStyle just leaves the optimization to Julia itself)
- guards are considered good alternatives to pin operators
So perhaps in our new rewrite, we should consider removing this operator completely? But it would less convenient (basically meaning needs to write another layer of the match in practice) when a pattern need to re-use the first matched variable's value.
Yes, we need to consider this in our new rewrite.
We can learn from Python's design: https://peps.python.org/pep-0636/
A.b == matching by value is pretty okay as the introduction in Python doesn't cause issues in practice. We don't need pin operators in this case.
However, I'm not sure how to support matching a value that comes from the local scope, or we just do not support this? Actually, this is only supported in pattern matching languages that support pin operators. See this:
function func(local_var)
@match value begin
&local_var => ...
end
end
True, I think we still need a distinguish of local/global scope just because this is not available inside a Julia macro, but if somehow we can get macro caller scope, this would not be necessary the rule is the same as other cases if the name is defined then match the value, instead of assigning a new variable.
It seems we have no choice but to have something like this because the support has to be implemented as a macro instead of after-scope gets resolved. It's just we need to think about the operators pred more so perhaps need something else other than &
I think we should just use $, the meaning of this is actually clear outside quotes, e.g
function Tree.print_node(io::IO, node::SpatialModulationType)
@match node begin
$SpatialModulationType.Global => print(io, "Global")
$SpatialModulationType.ScaledLocations(_) => print(io, "ScaledLocations")
end
end
just means we insert a value from outside to the pattern expression, so it will reference to whatever SpatialModulationType points to within this scope. Within a quote expression, we just need to do it twice
@match ex begin
:($($x) + 1) => true
_ => false
end
this means we reference an external value and then insert it into the pattern, if x = 1 this is equivalent to writing
@match ex begin
:($(1) + 1) => true
_ => false
end
I think you are correct. I'm checking expressions created from Julia parsers could support this.
Here is a use case for &. Suppose I want to rewrite x + x to 2x for any x.
julia> @match :(x + x) :($e + $f) && if e == f end => :(2($e))
:(2x)
julia> @match :(x + x) :($e + $(&e)) => :(2($e))
:(2x)
I don't think either of these syntaxes is especially pretty, but the & is probably nicer.