Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: match expression with unification


Miroslav Olšák (Apr 19 2021 at 09:10):

Is there a way to pattern match on an expression with definition unfolding (like tactic.unify does)? For example, how to make the following function get_first_summand working also in the other cases?

meta def get_first_summand (e : expr) : tactic expr
:=
do
  -- tactic.unify `(nat.add 2 5) e, -- tactic.unify would work but there is no space for variables
  `(nat.add %%a %%_)  return e,
  return a

-- succeeds with 2
run_cmd tactic.trace (get_first_summand `(nat.add 2 5))

def new_func (n : ) :  := (nat.add n 5)

-- fails
run_cmd tactic.trace (get_first_summand `(new_func 2))
run_cmd tactic.trace (get_first_summand `(2 + 5))

I don't want to just add more cases for new_func or has_add.add because function new_func could be defined after the tactic.

Jannis Limperg (Apr 19 2021 at 09:16):

You'll have to use whnf or dsimp to reduce the expression to head-normal form, then match on it. There is unfortunately no way to directly match 'up to conversion'. You'll also have to decide what transparency to use; this controls which constants get unfolded during the whnf reduction.

Jannis Limperg (Apr 19 2021 at 09:18):

(Actually, you could unify with a term containing metavariables, then read those. But that's probably more expensive.)

Miroslav Olšák (Apr 19 2021 at 09:20):

I do not need too much efficiency in this case, how do I construct an expression with metavariables?

Jannis Limperg (Apr 19 2021 at 09:25):

I guess there's no quotation for mvars, so you'll have to build it manually. Something like this (untested):

summand1 <- mk_mvar nat,
summand2 <- mk_mvar nat,
let pattern := `(nat.add %summand1 %summand2),
unify e pattern,
summand1 <- instantiate_mvars summand1,
pure summand1

I should stress this is highly unidiomatic; I just had this idea. YMMV.

Miroslav Olšák (Apr 19 2021 at 09:28):

thanks, I will play with it, maybe whnf will suffice (but I don't want to expand what could be expanded in the match, so I will have to play with reducibility a bit)

Miroslav Olšák (Apr 19 2021 at 09:42):

For completeness, this is a working code with metavariables.

meta def get_first_summand (e : expr) : tactic expr
:=
do
  summand1 <- tactic.mk_mvar,
  summand2 <- tactic.mk_mvar,
  let pattern := `(nat.add %%summand1 %%summand2),
  tactic.unify e pattern,
  summand1 <- tactic.instantiate_mvars summand1,
  return summand1

Last updated: Dec 20 2023 at 11:08 UTC