Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

& might be a bad choice for de-interpolation #160

Open
Roger-luo opened this issue Mar 21, 2023 · 7 comments
Open

& might be a bad choice for de-interpolation #160

Roger-luo opened this issue Mar 21, 2023 · 7 comments
Labels
help wanted Extra attention is needed

Comments

@Roger-luo
Copy link
Collaborator

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

@thautwarm thautwarm added the help wanted Extra attention is needed label Mar 30, 2023
@thautwarm
Copy link
Owner

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:

  1. pin operators can be confusing as $ exists
  2. pin operators are difficult to optimize (MLStyle just leaves the optimization to Julia itself)
  3. guards are considered good alternatives to pin operators

@Roger-luo
Copy link
Collaborator Author

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.

@thautwarm
Copy link
Owner

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

@Roger-luo
Copy link
Collaborator Author

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 &

@Roger-luo
Copy link
Collaborator Author

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

@thautwarm
Copy link
Owner

I think you are correct. I'm checking expressions created from Julia parsers could support this.

@jariji
Copy link
Contributor

jariji commented Feb 22, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants