77 lines
3.1 KiB
Text
77 lines
3.1 KiB
Text
/-
|
|
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import init.meta.tactic init.function
|
|
|
|
namespace tactic
|
|
|
|
/- Return target after instantiating metavars and whnf -/
|
|
private meta def target' : tactic expr :=
|
|
target >>= instantiate_mvars >>= whnf
|
|
|
|
meta def get_constructors_for (e : expr) : tactic (list name) :=
|
|
do env ← get_env,
|
|
I ← return e.get_app_fn.const_name,
|
|
when (¬env.is_inductive I) (fail "constructor tactic failed, target is not an inductive datatype"),
|
|
return $ env.constructors_of I
|
|
|
|
private meta def try_constructors (cfg : apply_cfg): list name → tactic unit
|
|
| [] := fail "constructor tactic failed, none of the constructors is applicable"
|
|
| (c::cs) := (mk_const c >>= λ e, apply_core e cfg >> return ()) <|> try_constructors cs
|
|
|
|
meta def constructor (cfg : apply_cfg := {}): tactic unit :=
|
|
target' >>= get_constructors_for >>= try_constructors cfg
|
|
|
|
meta def econstructor : tactic unit :=
|
|
constructor {new_goals := new_goals.non_dep_only}
|
|
|
|
meta def fconstructor : tactic unit :=
|
|
constructor {new_goals := new_goals.all}
|
|
|
|
meta def left : tactic unit :=
|
|
do tgt ← target',
|
|
[c₁, c₂] ← get_constructors_for tgt | fail "left tactic failed, target is not an inductive datatype with two constructors",
|
|
mk_const c₁ >>= apply
|
|
|
|
meta def right : tactic unit :=
|
|
do tgt ← target',
|
|
[c₁, c₂] ← get_constructors_for tgt | fail "left tactic failed, target is not an inductive datatype with two constructors",
|
|
mk_const c₂ >>= apply
|
|
|
|
meta def constructor_idx (idx : nat) : tactic unit :=
|
|
do cs ← target' >>= get_constructors_for,
|
|
some c ← return $ cs.nth (idx - 1) | fail "constructor_idx tactic failed, target is an inductive datatype, but it does not have sufficient constructors",
|
|
mk_const c >>= apply
|
|
|
|
meta def split : tactic unit :=
|
|
do [c] ← target' >>= get_constructors_for | fail "split tactic failed, target is not an inductive datatype with only one constructor",
|
|
mk_const c >>= apply
|
|
|
|
open expr
|
|
|
|
private meta def apply_num_metavars : expr → expr → nat → tactic expr
|
|
| f ftype 0 := return f
|
|
| f ftype (n+1) := do
|
|
pi m bi d b ← whnf ftype,
|
|
a ← mk_meta_var d,
|
|
new_f ← return $ f a,
|
|
new_ftype ← return $ b.instantiate_var a,
|
|
apply_num_metavars new_f new_ftype n
|
|
|
|
meta def existsi (e : expr) : tactic unit :=
|
|
do [c] ← target' >>= get_constructors_for | fail "existsi tactic failed, target is not an inductive datatype with only one constructor",
|
|
fn ← mk_const c,
|
|
fn_type ← infer_type fn,
|
|
n ← get_arity fn,
|
|
when (n < 2) (fail "existsi tactic failed, constructor must have at least two arguments"),
|
|
t ← apply_num_metavars fn fn_type (n - 2),
|
|
eapply (app t e),
|
|
t_type ← infer_type t >>= whnf,
|
|
e_type ← infer_type e,
|
|
(guard t_type.is_pi <|> fail "existsi tactic failed, failed to infer type"),
|
|
(unify t_type.binding_domain e_type <|> fail "existsi tactic failed, type mismatch between given term witness and expected type")
|
|
|
|
end tactic
|