feat: simproc for functions out of Subtype feat: simproc for functions out of Subtype
diff --git a/src/Init/Data/List/Attach.lean b/src/Init/Data/List/Attach.lean index 985c5ca..efc2bda 100644 --- a/src/Init/Data/List/Attach.lean +++ b/src/Init/Data/List/Attach.lean
@@ -548,4 +548,12 @@ (l.attachWith p H).count a = l.count ↑a := Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attachWith _ _ _ +@[simp] theorem map_attach_comp_subtype_val {l : List α} : + l.attach.map (f ∘ Subtype.val) = l.map f := by + simp [map_attach] + +@[simp] theorem map_attachWith_comp_subtype_val {l : List α} {P : α → Prop} {H} : + (l.attachWith P H).map (f ∘ Subtype.val) = l.map f := by + simp [map_attachWith] + end List
diff --git a/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs.lean b/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs.lean index 067b280..9d5c233 100644 --- a/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs.lean +++ b/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs.lean
@@ -14,3 +14,4 @@ import Lean.Meta.Tactic.Simp.BuiltinSimprocs.BitVec import Lean.Meta.Tactic.Simp.BuiltinSimprocs.List import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Array +import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Subtype
diff --git a/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs/Subtype.lean b/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs/Subtype.lean new file mode 100644 index 0000000..febd328 --- /dev/null +++ b/src/Lean/Meta/Tactic/Simp/BuiltinSimprocs/Subtype.lean
@@ -0,0 +1,57 @@ +/- +Copyright (c) 2024 Lean FRO. All Rights Reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison +-/ +prelude +import Lean.Meta.LitValues +import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat + +namespace Subtype +open Lean Meta Simp + +/-- +Rewrite a function `f : { x // p x } → α` in the form `f' ∘ Subtype.val` if (syntactically) possible. +-/ +def asCompVal (f : Expr) : MetaM (Option Expr) := do + let Expr.lam n d b bi := f | return none + let_expr Subtype α p := d | return none + let some b' := replaceValBVar 0 b | return none + let f' := .lam n α b' bi + let r ← mkAppM ``Function.comp #[f', ← mkAppOptM ``Subtype.val #[α, p]] + return (some r) +where + /-- + Walk down `e`, replacing `Subtype.val #k` with `#k`, + and returning `none` if there are any `#k`s not in this position. + -/ + replaceValBVar (k : Nat) (e : Expr) : Option Expr := + match e with + | .app (.app (.app (.const n _) _) _) (.bvar k') => + if k = k' then + if n = `Subtype.val then return .bvar k else none + else + return e + | .bvar i => if i = k then none else return e + | .app f x => return .app (← replaceValBVar k f) (← replaceValBVar k x) + | .lam n d b bi => return .lam n (← replaceValBVar k d) (← replaceValBVar (k+1) b) bi + | .forallE n d b bi => return .forallE n (← replaceValBVar k d) (← replaceValBVar (k+1) b) bi + | .letE n t v b d => return .letE n (← replaceValBVar k t) (← replaceValBVar k v) (← replaceValBVar (k+1) b) d + | .proj n i e => return .proj n i (← replaceValBVar k e) + | .mdata data e => return .mdata data (← replaceValBVar k e) + | .lit _ + | .const _ _ + | .sort _ + | .mvar _ + | .fvar _ => return e + +/-- +Simplify `l.map f`, where `l : List { x // p x }` and `f` factors as `f' ∘ Subtype.val`, +to `l.map (f' ∘ Subtype.val)`. + -/ +builtin_dsimproc [simp, seval] reduceMapSubtype (List.map _ _) := fun e => do + let_expr List.map _ _ f l ← e | return .continue + let some f' ← asCompVal f | return .continue + return .done <| (← mkAppM ``List.map #[f', l]) + +end Subtype
diff --git a/tests/lean/run/simprocSubtype.lean b/tests/lean/run/simprocSubtype.lean new file mode 100644 index 0000000..c9c0ec1 --- /dev/null +++ b/tests/lean/run/simprocSubtype.lean
@@ -0,0 +1,8 @@ +inductive Tree where | node : List Tree → Tree + +def Tree.rev : Tree → Tree + | node ts => .node (ts.attach.reverse.map (fun ⟨t, _⟩ => t.rev)) + +@[simp] theorem Tree.rev_def (ts : List Tree) : + Tree.rev (.node ts) = .node (ts.reverse.map rev) := by + simp [Tree.rev]