lean4-htt/library/init/meta/constructor_tactic.lean

77 lines
3.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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.extract_opt_auto_param.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 (list (name × expr))
| [] := fail "constructor tactic failed, none of the constructors is applicable"
| (c::cs) := (mk_const c >>= λ e, apply e cfg) <|> try_constructors cs
meta def constructor (cfg : apply_cfg := {}): tactic (list (name × expr)) :=
target' >>= get_constructors_for >>= try_constructors cfg
meta def econstructor : tactic (list (name × expr)) :=
constructor {new_goals := new_goals.non_dep_only}
meta def fconstructor : tactic (list (name × expr)) :=
constructor {new_goals := new_goals.all}
meta def left : tactic (list (name × expr)) :=
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 (list (name × expr)) :=
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 (list (name × expr)) :=
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 (list (name × expr)) :=
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