JuliaServices / Match.jl

Advanced Pattern Matching for Julia
https://juliaservices.github.io/Match.jl/latest/
Other
240 stars 22 forks source link

Is it possible to use match variables outside the @match block ? #96

Closed Lincoln-Hannah closed 9 months ago

Lincoln-Hannah commented 1 year ago

e.g.

@match [1,2,3,4] begin
    [1,x,y,4] =>  "good match"
     _        =>  _
end

Z = x + y 

I have a @match block with 20 matches. Most of them extract the same 2 variables x, y from the vector input. It would be nice to have x and y available after the block. Otherwise I have to put them in every match output.

=> (x,y,...)
=> (x,y...  )
=> (x,y...
gafter commented 1 year ago

The short answer is "no". The pattern variables in each branch are distinct from one another.

However, one way to accomplish that is to use a single-branch match and use a disjunctive (or) pattern. In face, you can use the @ismatch macro (with disjunction) to accomplish that. It leaves the variable bindings in the enclosing scope.

Lincoln-Hannah commented 1 year ago

Thanks so much! this is awesome. So concise.

A=B=C=""
@ismatch  [1,2,3]  (

    [A,B,C] where A ∈ [10,11]  ||
    [A,B,C] where A ∈ [20,21]  ||
    [1,2,C] where C ∈ [ 3, 4]
)

Is it possible to do it like this?

A=B=C=""
@ismatch  [1,2,3]  ( any[

    [A,B,C] where A ∈ [10,11] 
    [A,B,C] where A ∈ [20,21] 
    [1,2,C] where C ∈ [ 3, 4]
])
gafter commented 1 year ago

Is it possible to do it like this?

That isn't currently a supported syntax. Is there a reason that would be better?

You can also do this:

A=B=C=""
@ismatch  [1,2,3]  (
    [10|11,B,C] ||
    [20|21,B,C] ||
    [1,2,3|4]
)
Lincoln-Hannah commented 1 year ago
A=B=C=""
@ismatch  [1,2,3]  (
    [10|11,B,C] ||
    [20|21,B,C] ||
    [1,2,3|4]
)

This will match B and C but not A yeah?

I'm noticing a bug now that I think wasn't there before but I've tried versions 1.2 and 2.0 with same result. It seems to only assign values to variables that are in all matching options.

A=""
@ismatch  [1,2]  (    [1,A]   ||     [2,A] )        #works
@ismatch  [1,2]  (    [1,A]   ||     [2] )          #doesn't put a value in A

I like the below syntax because you know from the first line any that you can consider the following lines separately. With the || syntax, any of them could be && or something else - just requires a bit more thought to interpret.

A=B=C=""
@ismatch  [1,2,3]  ( any[

    [A,B,C] where A ∈ [10,11] 
    [A,B,C] where A ∈ [20,21] 
    [1,2,C] where C ∈ [ 3, 4]
])

Could also be written as below.

@ismatch  [1,2,3]  ( any[

    [A∈ [10,11] ,B, C              ] 
    [A∈ [20,21] ,B, C              ] 
    [1,                2,C ∈ [ 3, 4]  ]
])
gafter commented 1 year ago
@ismatch  [1,2,3]  (

    [A && 10|11 ,B, C        ] ||
    [A && 20|21 ,B, C        ] ||
    [1,          2, C && 3|4 ]
)

The advantage of placing the value test in the pattern is that @match can generate better code.

Lincoln-Hannah commented 1 year ago

This variable && is nice syntax I wasn't aware of thank you.

Unfortunately I get the same issue on Julia Hub as my local machine. In the below code only A and B will be populated. C isn't populated because it isn't in the last line

A=B=C=""
@ismatch    [10,9,8]  (

    [A && 10|11|12 ,    B,          C        ]  ||
    [A && 20|21 ,       B,          C        ]    ||
    [A && 1|2,          B && 2|3 ]              

)

Just a thought, instead of having to initiate the variables prior to the @ismatch block e.g. A=B=C=""
Would it be possible to list them at the start of the block e.g. @ismatch (vars=A,B,C) [10,9,8] ( ... such that unmatched variables take the value nothing or ""

gafter commented 9 months ago

Just a thought, instead of having to initiate the variables prior to the @ismatch block e.g. A=B=C="" Would it be possible to list them at the start of the block e.g. @ismatch (vars=A,B,C) [10,9,8] ( ... such that unmatched variables take the value nothing or ""

Yes, that would be possible. I'll open a separate feature request detailing this idea.