Zulip Chat Archive
Stream: lean4
Topic: Deriving operations for structures
Tomas Skrivan (Apr 25 2024 at 16:36):
Are there deriving functions for deriving arithmetic operations for structures?
I would like to write
structure Vec2 (X : Type) where
(x y : X)
deriving Add, SMul ℝ
which would add instances Add X → Add (Vec2 X) and SMul ℝ X → SMul ℝ (Vec2 X)
A more complicated example:
structure Ball (R X : Type) where
center : R
radius : X
deriving Add, SMul R
which would add instances Add R → Add X → Add (Ball R X) and Mul R → SMul R X → SMul (Ball R X).
Is there anything like this in mathlib/lean already? I couldn't find anything. Has anyone thought about this problem? I have done few attempts but I still do not have anything satisfactory.
Kyle Miller (Apr 25 2024 at 17:22):
Here's an approach using Mathlib:
structure Vec2 (X : Type) where
(x y : X)
def Add.ofEquiv {X Y : Type*} [Add X] (f : X ≃ Y) : Add Y where
add a b := f (f.symm a + f.symm b)
instance {X Y : Type*} [Add X] [Add Y] : Add ((_ : X) × Y) where
add | ⟨x1, y1⟩, ⟨x2, y2⟩ => ⟨x1 + x2, y1 + y2⟩
instance (X : Type) [Add X] : Add (Vec2 X) :=
Add.ofEquiv (proxy_equiv% _)
With some more work, you could turn this into a derive handler (or at least a command, since SMul ℝ isn't supported by the deriving syntax). See for example the Fintype handler.
Kyle Miller (Apr 25 2024 at 17:23):
Or this unfinished PR for deriving LinearOrders: #3251
Tomas Skrivan (Apr 25 2024 at 17:24):
I saw the Fintype approach, I'm a bit worried about the generated code. I don't want to just prove theorems.
Kyle Miller (Apr 25 2024 at 17:25):
The least efficient part about the generated code is how it handles multiple constructors, but since structures have just one constructor, it might not be so bad.
Kyle Miller (Apr 25 2024 at 17:25):
It's worth evaluating it, and seeing what you can do to get it to inline everything in sight if necessary.
Tomas Skrivan (Apr 25 2024 at 17:26):
Yeah I might write some tactic that unfolds lots of the definitions involved.
Kyle Miller (Apr 25 2024 at 17:27):
For example, if you have a reduce% term elaborator, you could write
instance (X : Type) [Add X] : Add (Vec2 X) :=
reduce% (Add.ofEquiv (proxy_equiv% _))
Tomas Skrivan (Apr 25 2024 at 17:28):
Sounds good, I will play around with this
Tomas Skrivan (Apr 25 2024 at 18:38):
So far so good, only one issue came up. Deriving instance for UniformSpace is a problem as it does not have instance for Sigma. Also I have some type classes that provide way simpler instance to Prod and I would prefer if proxy_equiv% would generate Prod if possible.
If I understand the code correctly I can alter defaultMkCtorProxyType to use Prod if possible. Not sure what are the downstream consequences of doing so.
Kyle Miller (Apr 25 2024 at 18:40):
I had to add a non-dependent Sigma instance for Add in the above code. Non-dependent sigma instances should have the same code as a Prod instance.
Kyle Miller (Apr 25 2024 at 18:40):
I think there's no problem adding Prod to the list of types that proxy_type% generates. It just increases the complexity a bit, and you have to be sure all the documentation that promises "if you implement instances for this list of types, then deriving handlers will work"
Tomas Skrivan (Apr 25 2024 at 18:48):
Kyle Miller said:
I had to add a non-dependent
Sigmainstance forAddin the above code. Non-dependent sigma instances should have the same code as a Prod instance.
Ah that is right, just using Sigma is probably ok. I have to play around with it a bit more.
Last updated: May 02 2025 at 03:31 UTC