lean4-htt/src/Lean/Meta/Tactic/FVarSubst.lean
2025-07-25 12:02:51 +00:00

88 lines
2.6 KiB
Text

/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Mario Carneiro
-/
module
prelude
public import Lean.Data.AssocList
public import Lean.Expr
public import Lean.LocalContext
public import Lean.Util.ReplaceExpr
public section
namespace Lean.Meta
/--
Some tactics substitute hypotheses with expressions.
We track these substitutions using `FVarSubst`.
It is just a mapping from the original FVarId (internal) name
to an expression. The free variables occurring in the expression must
be defined in the new goal. -/
structure FVarSubst where
map : AssocList FVarId Expr := {}
deriving Inhabited
namespace FVarSubst
def empty : FVarSubst := {}
def isEmpty (s : FVarSubst) : Bool :=
s.map.isEmpty
def contains (s : FVarSubst) (fvarId : FVarId) : Bool :=
s.map.contains fvarId
/-- Add entry `fvarId |-> v` to `s` if `s` does not contain an entry for `fvarId`. -/
def insert (s : FVarSubst) (fvarId : FVarId) (v : Expr) : FVarSubst :=
if s.contains fvarId then s
else
let map := s.map.mapVal fun e => e.replaceFVarId fvarId v;
{ map := map.insertNew fvarId v }
def erase (s : FVarSubst) (fvarId : FVarId) : FVarSubst :=
{ map := s.map.erase fvarId }
def find? (s : FVarSubst) (fvarId : FVarId) : Option Expr :=
s.map.find? fvarId
def get (s : FVarSubst) (fvarId : FVarId) : Expr :=
match s.map.find? fvarId with
| none => mkFVar fvarId -- it has not been replaced
| some v => v
/-- Given `e`, for each `(x => v)` in `s` replace `x` with `v` in `e` -/
def apply (s : FVarSubst) (e : Expr) : Expr :=
if s.map.isEmpty then e
else if !e.hasFVar then e
else e.replace fun e => match e with
| Expr.fvar fvarId => match s.map.find? fvarId with
| none => e
| some v => v
| _ => none
def domain (s : FVarSubst) : List FVarId :=
s.map.foldl (init := []) fun r k _ => k :: r
def any (p : FVarId → Expr → Bool) (s : FVarSubst) : Bool :=
s.map.any p
/--
Constructs a substitution consisting of `s` followed by `t`.
This satisfies `(s.append t).apply e = t.apply (s.apply e)`
-/
def append (s t : FVarSubst) : FVarSubst :=
s.1.foldl (fun s' k v => s'.insert k (t.apply v)) t
end FVarSubst
end Meta
def LocalDecl.applyFVarSubst (s : Meta.FVarSubst) : LocalDecl → LocalDecl
| LocalDecl.cdecl i id n t bi k => LocalDecl.cdecl i id n (s.apply t) bi k
| LocalDecl.ldecl i id n t v nd k => LocalDecl.ldecl i id n (s.apply t) (s.apply v) nd k
abbrev Expr.applyFVarSubst (s : Meta.FVarSubst) (e : Expr) : Expr :=
s.apply e
end Lean