Zulip Chat Archive
Stream: CSLib
Topic: Little addition to HasSubstitution
Fabrizio Montesi (Jan 21 2026 at 12:54):
@Chris Henson What do you think of adding to HasSubstitution the requirement that substitution never touches things it cannot find? I'm finding myself repeating this over and over in the preparation of a general framework for logics in CSLib.
For example:
/-- Typeclass for substitution relations and access to their notation. -/
class HasSubstitution (α : Type u) (β : Type v) (γ : Type w) where
/-- Substitution function. Replaces `x` in `t` with `t'`. -/
subst (t : α) (x : β) (t' : γ) : α
/-- Substitution does not add elements. -/
subst_mem_eq [Membership β α] {t : α} {x : β} {t' : γ} (h : x ∉ t) : subst t x t' = t
Chris Henson (Jan 21 2026 at 13:15):
This is fine if it is put in a class extending this one. My reasoning:
- In general we don't want to tie propositions to very general notation typeclasses
- It is preferable for any propositions like this to use the substitution notation, which can't happen if it's in the same class.
- For things like System F, where there are multiple instances for substitution, this is true but a little awkward
Fabrizio Montesi (Jan 21 2026 at 13:40):
You mean, a class that extends HasSubstitution with subst_mem_eq?
Fabrizio Montesi (Jan 21 2026 at 13:44):
Ah, of course (I initially misinterpreted what you meant by proposition).
I agree. Also, there are other properties we'll probably add as classes. Any idea for what we could call the extended class?
Chris Henson (Jan 21 2026 at 13:53):
If you anticipate multiple such classes the pattern could be Lawful + <part that changes> + Subst. So maybe LawfulMemSubst here? (Trying to keep it reasonably short here with some abbreviation...)
Fabrizio Montesi (Jan 21 2026 at 13:55):
Sounds good for when there's no established name (like idempotent, etc.).
Fabrizio Montesi (Jan 22 2026 at 07:54):
here's a proposal in line with 'HAdd' from Lean core:
/--
Typeclass for heterogeneous substitutions (all input types can differ) and access to their notation.
-/
class HSubst (α : Type u) (β : Type v) (γ : Type w) where
/-- Substitution function. Replaces `x` in `t` with `t'`. -/
subst (t : α) (x : β) (t' : γ) : α
/-- Notation for substitution. -/
notation t:max "[" x ":=" t' "]" => HSubst.subst t x t'
/-- Typeclass for heterogeneous substitutions that require membership for modification. -/
class MemHSubst (α : Type u) (β : Type v) (γ : Type w) extends HSubst α β γ where
/-- Substituting a non-present element is the identity. -/
subst_mem_eq [Membership β α] {t : α} {x : β} {t' : γ} (h : x ∉ t) : subst t x t' = t
Eric Wieser (Jan 22 2026 at 07:56):
subst_mem_eq [Membership β α] seems like it makes this useless
Eric Wieser (Jan 22 2026 at 07:56):
Because that says "for every possible definition of membership, substitution is a no-op":
theorem bad {α β γ} [MemHSubst α β γ] {t : α} {x : β} {t' : γ} : HSubst.subst t x t' = t :=
@MemHSubst.subst_mem_eq _ _ _ _ ⟨fun _ _ => False⟩ _ _ _ False.elim
Eric Wieser (Jan 22 2026 at 07:57):
You want to say "for the canonical one", which means the [Membership β α] needs to be a parameter of the typeclass, not a quantifier in a field
Fabrizio Montesi (Jan 22 2026 at 07:57):
only MemHSubsts, and only if x ∉ t
Fabrizio Montesi (Jan 22 2026 at 07:57):
huh
Fabrizio Montesi (Jan 22 2026 at 07:57):
I see what you mean
Fabrizio Montesi (Jan 22 2026 at 07:58):
this, right?
/-- Typeclass for heterogeneous substitutions that require membership for modification. -/
class MemHSubst (α : Type u) (β : Type v) (γ : Type w) [Membership β α] extends HSubst α β γ where
/-- Substituting a non-present element is the identity. -/
subst_mem_eq {t : α} {x : β} {t' : γ} (h : x ∉ t) : subst t x t' = t
Eric Wieser (Jan 22 2026 at 07:59):
yes, that's safe
Fabrizio Montesi (Jan 22 2026 at 07:59):
good catch, thx :)
Fabrizio Montesi (Jan 22 2026 at 08:00):
.... grind has proven it just works for linear logic sequents without me doing anything. I love these moments :grinning_face_with_smiling_eyes:
instance [DecidableEq (Proposition Atom)] :
MemHSubst (Sequent Atom) (Proposition Atom) (Proposition Atom) where
subst Γ a b := if a ∈ Γ then Γ.erase a |> insert b else Γ
subst_mem_eq := by grind
Eric Wieser (Jan 22 2026 at 08:01):
I mean the proof is probably just := if_neg so this isn't particularly impressive
Fabrizio Montesi (Jan 22 2026 at 08:03):
I tried if_neg and it didn't work
Fabrizio Montesi (Jan 22 2026 at 08:04):
mmmh but you're right, so it's probably due to something silly with the parameters...
Fabrizio Montesi (Jan 22 2026 at 08:04):
this works:
subst_mem_eq := by
intro _ _ _ _
apply if_neg
assumption
Eric Wieser (Jan 22 2026 at 08:13):
I would guess that subst_mem_eq h := if_neg h does too
Fabrizio Montesi (Jan 22 2026 at 08:30):
It does, thanks for the golfing!
Last updated: Feb 28 2026 at 14:05 UTC