/- Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura Converter monad for building simplifiers. -/ prelude import init.meta.interactive init.meta.converter.conv namespace conv meta def save_info (p : pos) : conv unit := do s ← tactic.read, tactic.save_info_thunk p (λ _, s.to_format tt) meta def step {α : Type} (c : conv α) : conv unit := c >> return () meta def istep {α : Type} (line0 col0 line col : nat) (c : conv α) : conv unit := tactic.istep line0 col0 line col c meta def execute (c : conv unit) : tactic unit := c meta def solve1 (c : conv unit) : conv unit := tactic.solve1 $ c >> tactic.repeat tactic.reflexivity namespace interactive open lean open lean.parser open interactive open interactive.types meta def itactic : Type := conv unit meta def skip : conv unit := conv.skip meta def whnf : conv unit := conv.whnf meta def dsimp (no_dflt : parse only_flag) (es : parse tactic.simp_arg_list) (attr_names : parse with_ident_list) (cfg : tactic.dsimp_config := {}) : conv unit := do (s, u) ← tactic.mk_simp_set no_dflt attr_names es, conv.dsimp (some s) u cfg meta def trace_lhs : conv unit := lhs >>= tactic.trace meta def change (p : parse texpr) : conv unit := tactic.i_to_expr p >>= conv.change meta def congr : conv unit := conv.congr meta def funext : conv unit := conv.funext private meta def is_relation : conv unit := (lhs >>= tactic.relation_lhs_rhs >> return ()) <|> tactic.fail "current expression is not a relation" meta def to_lhs : conv unit := is_relation >> congr >> tactic.swap >> skip meta def to_rhs : conv unit := is_relation >> congr >> skip meta def done : conv unit := tactic.done meta def find (p : parse parser.pexpr) (c : itactic) : conv unit := do (r, lhs, _) ← tactic.target_lhs_rhs, pat ← tactic.pexpr_to_pattern p, s ← simp_lemmas.mk_default, -- to be able to use congruence lemmas @[congr] (found, new_lhs, pr) ← tactic.ext_simplify_core ff {zeta := ff, beta := ff, single_pass := tt, eta := ff, proj := ff, fail_if_unchanged := ff, memoize := ff} s (λ u, return u) (λ found s r p e, do guard (not found), matched ← (tactic.match_pattern_core reducible pat e >> return tt) <|> return ff, guard matched, ⟨new_e, pr⟩ ← c.convert e r, return (tt, new_e, pr, ff)) (λ a s r p e, tactic.failed) r lhs, when (not found) $ tactic.fail "find converter failed, pattern was not found", update_lhs new_lhs pr meta def for (p : parse parser.pexpr) (occs : parse (list_of small_nat)) (c : itactic) : conv unit := do (r, lhs, _) ← tactic.target_lhs_rhs, pat ← tactic.pexpr_to_pattern p, s ← simp_lemmas.mk_default, -- to be able to use congruence lemmas @[congr] (found, new_lhs, pr) ← tactic.ext_simplify_core 1 {zeta := ff, beta := ff, single_pass := tt, eta := ff, proj := ff, fail_if_unchanged := ff, memoize := ff} s (λ u, return u) (λ i s r p e, do matched ← (tactic.match_pattern_core reducible pat e >> return tt) <|> return ff, guard matched, if i ∈ occs then do ⟨new_e, pr⟩ ← c.convert e r, return (i+1, new_e, some pr, tt) else return (i+1, e, none, tt)) (λ a s r p e, tactic.failed) r lhs, update_lhs new_lhs pr meta def simp (no_dflt : parse only_flag) (hs : parse tactic.simp_arg_list) (attr_names : parse with_ident_list) (cfg : tactic.simp_config_ext := {}) : conv unit := do (s, u) ← tactic.mk_simp_set no_dflt attr_names hs, (r, lhs, rhs) ← tactic.target_lhs_rhs, (new_lhs, pr) ← tactic.simplify s u lhs cfg.to_simp_config r cfg.discharger, update_lhs new_lhs pr, return () meta def guard_lhs (p : parse texpr) : tactic unit := do t ← lhs, tactic.interactive.guard_expr_eq t p section rw open tactic.interactive (rw_rules rw_rule get_rule_eqn_lemmas to_expr') open tactic (rewrite_cfg) private meta def rw_lhs (h : expr) (cfg : rewrite_cfg) : conv unit := do l ← conv.lhs, (new_lhs, prf, _) ← tactic.rewrite h l cfg, update_lhs new_lhs prf private meta def rw_core (rs : list rw_rule) (cfg : rewrite_cfg) : conv unit := rs.mmap' $ λ r, do save_info r.pos, eq_lemmas ← get_rule_eqn_lemmas r, orelse' (do h ← to_expr' r.rule, rw_lhs h {cfg with symm := r.symm}) (eq_lemmas.mfirst $ λ n, do e ← tactic.mk_const n, rw_lhs e {cfg with symm := r.symm}) (eq_lemmas.empty) meta def rewrite (q : parse rw_rules) (cfg : rewrite_cfg := {}) : conv unit := rw_core q.rules cfg meta def rw (q : parse rw_rules) (cfg : rewrite_cfg := {}) : conv unit := rw_core q.rules cfg end rw end interactive end conv namespace tactic namespace interactive open lean open lean.parser open interactive open interactive.types open tactic local postfix `?`:9001 := optional private meta def conv_at (h_name : name) (c : conv unit) : tactic unit := do h ← get_local h_name, h_type ← infer_type h, (new_h_type, pr) ← c.convert h_type, replace_hyp h new_h_type pr, return () private meta def conv_target (c : conv unit) : tactic unit := do t ← target, (new_t, pr) ← c.convert t, replace_target new_t pr, try tactic.triv, try (tactic.reflexivity reducible) meta def conv (loc : parse (tk "at" *> ident)?) (p : parse (tk "in" *> parser.pexpr)?) (c : conv.interactive.itactic) : tactic unit := do let c := match p with | some p := _root_.conv.interactive.find p c | none := c end, match loc with | some h := conv_at h c | none := conv_target c end end interactive end tactic