Zulip Chat Archive

Stream: new members

Topic: trouble with Eq.rec_on


James G (Nov 07 2025 at 06:54):

Hi all, I'm a software engineer with an interest in formal verification. I'm messing around with some silly types-containing-types stuff and I've run into a coercion problem, here's a restricted test case:

import Mathlib.Data.Fintype.Defs

structure ModelBTreeBase where
  Nil : Type
  Fork : Type
  Node : Type
  Node_def : Node = (Nil  Fork) -- can't find this equality if I define Node with :=
  fork_left : Fork -> Node -> Prop
  fork_left_unique :  f : Fork, ∃! n : Node, fork_left f n
  -- ...

structure ModelBTreeBaseMorph (b1 : ModelBTreeBase) (b2 : ModelBTreeBase) where
  Nil_map : b1.Nil -> b2.Nil
  Fork_map : b1.Fork -> b2.Fork
  Node_map : b1.Node -> b2.Node := b1.Node_def  b2.Node_def  Sum.map Nil_map Fork_map
  preserves_fork_left :  f : b1.Fork,  c : b1.Node,
    b1.fork_left f c -> b2.fork_left (Fork_map f) (Node_map c)
  -- ...

set_option pp.proofs true

def id_ (t : ModelBTreeBase) : ModelBTreeBaseMorph t t :=
   id, id, t.Node_def  Sum.map id id,
    by
      intros f c h
      simp
      _
      /-
        t : ModelBTreeBase
        f : t.Fork
        c : t.Node
        h : t.fork_left f c
        ⊢ t.fork_left f (Eq.rec (motive := fun x h ↦ x → x) id (Eq.symm t.Node_def) c)
      -/
  

It seems to me that that recursor application should be equal to c but it doesn't seem to be definitionally equal. I'm wondering if there's some magic I can invoke to fix this. Looking forward to chatting with you all :)

Robin Arnez (Nov 07 2025 at 07:08):

Type equality is almost always bad to deal with. Even if it's a bit more annoying, you'd be probably better off with inlining Node in the structure and making it a definition:

import Mathlib.Data.Fintype.Defs

structure ModelBTreeBase where
  Nil : Type
  Fork : Type
  fork_left : Fork -> Nil  Fork -> Prop
  fork_left_unique :  f : Fork, ∃! n : Nil  Fork, fork_left f n
  -- ...

abbrev ModelBTreeBase.Node (self : ModelBTreeBase) : Type := self.Nil  self.Fork

structure ModelBTreeBaseMorph (b1 : ModelBTreeBase) (b2 : ModelBTreeBase) where
  Nil_map : b1.Nil -> b2.Nil
  Fork_map : b1.Fork -> b2.Fork
  Node_map : b1.Node -> b2.Node := Sum.map Nil_map Fork_map
  preserves_fork_left :  f : b1.Fork,  c : b1.Node,
    b1.fork_left f c -> b2.fork_left (Fork_map f) (Node_map c)
  -- ...

def id_ (t : ModelBTreeBase) : ModelBTreeBaseMorph t t :=
  id, id, Sum.map id id, by intros; simpa

James G (Nov 07 2025 at 07:13):

Yeah, I was wondering if that was gonna be the solution. Alright, thanks

James G (Nov 07 2025 at 07:17):

Is abbrev different from def there?

Robin Arnez (Nov 07 2025 at 07:24):

The difference between abbrev and def is mostly when a declaration can be unfolded. For example, simp can't see through regular defs which might lead to problems since we've used Nil ⊕ Fork before which then, to simp and others, seem like two distinct things. abbrevs on the other hand, can always be unfolded and are also always eagerly unfolded in definitional equality problems.


Last updated: Dec 20 2025 at 21:32 UTC