MLStyle's vs MacroTools' @capture

Hey folks. I’ve been trying to figure out how to use MLStyle.Modules.AST.@capture for doing the same thing as MacroTools.@capture(ex, fn_(args__; kws__) | fn_(args__))

However, I can’t seem to come up with the syntax that does what | does in MacroTools.@capture. I assumed || would work since it seems to be used in regular MLStyle patterns, but it doesn’t seem like it:

In [20]: let ex = :(somefunction(param1, 666; a=5))
         @capture($fn($(args...);$(kw...)) || $fn($(args...)), ex)
         end
ERROR: matching non-exhaustive, at #= REPL[20]:2 =#

Both of those patterns work separately though, but only if the expression matches exactly:

In [24]: let ex = :(somefunction(param1, 666; a=5))
         @capture($fn($(args...);$(kw...)), ex)
         end
Dict{Symbol, Any} with 3 entries:
  :args => Any[:param1, 666]
  :fn   => :somefunction
  :kw   => Any[:($(Expr(:kw, :a, 5)))]

In [25]: let ex = :(somefunction(param1, 666))
         @capture($fn($(args...)), ex)
         end
Dict{Symbol, Any} with 2 entries:
  :args => Any[:param1, 666]
  :fn   => :somefunction

So eg. the pattern with keywords won’t match a call that doesn’t have them

In [26]: let ex = :(somefunction(param1, 666))
         @capture($fn($(args...);$(kw...)), ex)
         end
ERROR: matching non-exhaustive, at #= REPL[26]:2 =#

Seems a bit inconvenient that @capture throws if it gets an expression that doesn’t match the template.

@thautwarm would know best.

MacroTools is specific in this case, and pretty useful for maybe common usages. MLStyle instead keeps general (and sometimes useless) – although it might not be intentional for users to distinguish :(f(a...)) and :(f(a...;)), the nature exists in Julia.

For the reason why your pattern $fn($(args...);$(kw...)) does not match f(a, b) forms:

MLStyle holds the point that deconstruction should only work like reverting the construction.

julia> fn = :f
:f

julia> kws = []
Any[]

julia> args = [:a, :b]
2-element Vector{Symbol}:
 :a
 :b

julia> :($fn($(args...);$(kws...)))
:(f(a, b; ))  # <- see the semicolon here, it is not `f(a, b)`

You can see that with the expression :($fn($(args...);$(kws...))) you create the value :(f(a, b)), which also suggests that the pattern :($fn($(args...);$(kws...))) can match :(f(a, b; )) but not :(f(a, b)).

If you insist on using one-line match for this, maybe

MLStyle.Modules.AST.@capture($( :($fn($(args...)))  || :($fn($(args...);$(kw...))) ), ex)
1 Like

Ah now I understand what I did wrong with my attempt, I didn’t interpolate the whole pattern: @capture($fn($(args...);$(kw...)) || $fn($(args...)), ex).

Thank you for taking the time to explain things to me @thautwarm

You might be interested:

This library builds up on MLStyle.

2 Likes