lean4-htt/library/init/meta/constructor_tactic.lean
2017-02-08 15:33:25 -08:00

63 lines
2.4 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
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 : list name → tactic unit
| [] := fail "constructor tactic failed, none of the constructors is applicable"
| (c::cs) := (mk_const c >>= apply) <|> try_constructors cs
meta def constructor : tactic unit :=
target >>= get_constructors_for >>= try_constructors
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),
apply (app t e)
end tactic