Zulip Chat Archive
Stream: lean4
Topic: OfNat
François G. Dorais (Mar 02 2021 at 18:31):
How does OfNat
work?
inductive Bit | bit0 | bit1
instance : OfNat Bit 0 where ofNat := Bit.bit0
instance : OfNat Bit 1 where ofNat := Bit.bit1
#synth OfNat Bit 1 -- works: instOfNatBit_1
def test : Bit := 1 -- fails!?
Setting option trace.Meta.synthInstance
shows that test
doesn't find instOfNatBit_1
and only finds hasOfNatOfCoe
, but the #synth
finds both.
Daniel Selsam (Mar 02 2021 at 18:40):
The instance discrimination tree is not considering it in the def test
case. Currently, you need instance : OfNat Bit (noindex! 1) where ofNat := Bit.bit1
It is a known annoyance/gotcha and may be addressed.
François G. Dorais (Mar 02 2021 at 18:46):
Makes sense. I need to get used to these discrimination trees... Thanks!
Leonardo de Moura (Mar 02 2021 at 18:48):
@François G. Dorais The section Numerals
at https://leanprover.github.io/lean4/doc/typeclass.html explains how OfNat
works. The OfNat
instances must be indexed with "raw numerals". A "raw numeral" is a numeral that is not wrapped with OfNat.ofNat
.
You can create raw numerals using the notation natLit! n
. Here is your example with this notation.
inductive Bit | bit0 | bit1
instance : OfNat Bit (natLit! 0) where ofNat := Bit.bit0
instance : OfNat Bit (natLit! 1) where ofNat := Bit.bit1
def test1 : Bit := 1 -- works
def test0 : Bit := 0 -- works
The indexing will work as expected in the example above.
The noindex!
trick that @Daniel Selsam suggested works too, but if you have instances for different numerals, it will impact performance because Lean will not be able to filter them out using the discrimination trees.
François G. Dorais (Mar 02 2021 at 18:57):
I see, with this natLit!
version, #synth OfNat Bit 1
fails because the 1
is actually ofNat Nat (natLit! 1)
. Very interesting!
Last updated: Dec 20 2023 at 11:08 UTC