admin管理员组文章数量:1122832
def x := (0xFFFF : UInt8)
That compiles with no errors, which I find surprising given Lean's focus on proving correctness. Is there a good reason for this or is it simply an oversight? Also what does it do at runtime?
Bonus question: is there a more elegant way to write a UInt8 literal? E.g. in Rust you can do 0xFFu8
.
def x := (0xFFFF : UInt8)
That compiles with no errors, which I find surprising given Lean's focus on proving correctness. Is there a good reason for this or is it simply an oversight? Also what does it do at runtime?
Bonus question: is there a more elegant way to write a UInt8 literal? E.g. in Rust you can do 0xFFu8
.
1 Answer
Reset to default 1As mentioned in the comment, allowing this is not inconsistent with "focusing on proving correctness"; for bounded integers, numeric literals which exceed the bounds of the type are just defined to wrap around, so you can do #eval (0xFFFF : UInt8)
and will find that this evaluates to 255
.
The reasons for this behavior are mainly due to the way numeric literals are implemented in Lean 4. This works using a typeclass called OfNat
: when Lean encounters a numeric literal n
with expected type α
, it will attempt to synthesize an instance of OfNat α n
. So to get the desired behavior of rejecting literals which are out of bounds, you would need to somehow give an instance of OfNat α n
only if n
is small enough. This is not something that Lean's typeclass system supports in a straightforward way, so usually instances of OfNat
are defined for all n
and just implement some kind of wrapping behavior.
However, it is in fact possible to get the desired behavior using a somewhat obscure trick as demonstrated by the following code:
class When (p : Prop) [Decidable p] : Prop where
isTrue : p
instance : @When p (.isTrue h) := @When.mk p (_) h
-- Just a wrapper around `UInt8` to avoid clashing with the existing `OfNat` instance.
inductive MyUInt8 : Type where
| mk : UInt8 -> MyUInt8
instance [When (n < 256)] : OfNat MyUInt8 n where
ofNat := ⟨n.toUInt8⟩
#check (0xFF : MyUInt8) -- works
#check (0xFFFF : MyUInt8) -- failed to synthesize `OfNat MyUInt8 65535`
As discussed in the thread linked above, this approach has some limitations and therefore should not be considered a good solution to the problem, which is presumably why the Lean core developers do not use it in the OfNat
instaces defined in Lean core.
It is possible that the Lean developers will rework numeric literals in the future and introduce a less hacky and more general solution than the When
hack described above. Getting this right will be tricky, as it is a potentially very disruptive change, so I wouldn't expect to see any movement on this front soon.
Regarding your bonus question: if the expected type is known, you do not need to annotate the type for the numeric literal. So for example you could write
def x : UInt8 := 0xFF
本文标签: Why does Lean allow invalid UInt8 literalsStack Overflow
版权声明:本文标题:Why does Lean allow invalid UInt8 literals? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736281575a1926362.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
def x : Fin 3 := 37
(and thenexample : x = 1 := rfl
). It's not an oversight, and there is a reason (it saves you from having to supply the proof; it just wraps mod n, the idea is that it makes the code easier to write for the user). Whether you think it's a good reason is another matter (I also feel that this is a very dubious design decision). – Kevin Buzzard Commented yesterday