Zulip Chat Archive

Stream: new members

Topic: Cast weirdness


Neil Strickland (Mar 20 2019 at 11:27):

Can anyone help me to understand what is going on here?

lemma L (n : ) (p : n  0) (q : n < 1) : true :=
begin
 have h0 : n = n.nat_abs := int.eq_nat_abs_of_zero_le p,
 have h1 : (1 : ) = ((1 : ) : ) := dec_trivial,
 rw[h0,h1] at q,  -- Now q : ↑(int.nat_abs n) < ↑1
 have h2 : n.nat_abs < 1 := (@nat.cast_lt  _ n.nat_abs 1).mp q,
end

Lean rejects h2 with a type mismatch error. It says that q has the following type:

  @has_lt.lt int int.has_lt (@coe nat int (@coe_to_lift nat int (@coe_base nat int int.has_coe)) (int.nat_abs n))
    (@coe nat int (@coe_to_lift nat int (@coe_base nat int int.has_coe)) 1)

This seems sensible. However, it says that q is expected to have a different type, the description of which takes 70 lines or so. The difference seems to involve some kind of issue with typeclass inference and possibly different coercion functions, but I have not been able to understand this properly. I have tried a number of other syntax variants without any more success.

Mario Carneiro (Mar 20 2019 at 11:35):

The coercion nat -> int is not a specialization of the generic coercion nat -> A, so it has its own theorems

Mario Carneiro (Mar 20 2019 at 11:36):

I think this one is int.coe_nat_lt

Kevin Buzzard (Mar 20 2019 at 11:41):

https://github.com/leanprover-community/mathlib/blob/master/docs/extras/casts.md

Witness the asymmetry with nat -> int e.g.

import data.complex.basic

example (q : ) : (q : ) = (3 : )  q = 3 := int.of_nat_inj
example (q : ) : (q : ) = (3 : )  q = 3 := nat.cast_inj.1
example (q : ) : (q : ) = (3 : )  q = 3 := nat.cast_inj.1
example (q : ) : (q : ) = (3 : )  q = 3 := nat.cast_inj.1

example (q : ) : (q : ) = (3 : )  q = 3 := int.cast_inj.1
example (q : ) : (q : ) = (3 : )  q = 3 := int.cast_inj.1
example (q : ) : (q : ) = (3 : )  q = 3 := int.cast_inj.1

example (q : ) : (q : ) = (3 : )  q = 3 := rat.cast_inj.1
example (q : ) : (q : ) = (3 : )  q = 3 := rat.cast_inj.1

example (q : ) : (q : ) = (3 : )  q = 3 := complex.of_real_inj.1

The problem is that one of the constructors of int is int.of_nat and so for reasons apparently to do with efficiency they use it as the coercion. Given that "efficiency" and "definition of nat" together imply an immediate contradiction, I've never seen the logic -- but then again IANACS...

Mario Carneiro (Mar 20 2019 at 11:42):

note that nat is actually the most efficient VM natural numbers type, because of native support

Neil Strickland (Mar 20 2019 at 11:42):

Thanks. I now see that it also works to rewrite with int.nat_cast_eq_coe_nat at an appropriate point.

Kevin Buzzard (Mar 20 2019 at 11:52):

Just in case you didn't know:

import tactic.linarith

example (n : ) (p : n  0) (q : n < 1) : n = 0 := by linarith

Gun Pinyo (Aug 11 2019 at 23:29):

Hi there, I have a question regarding coercion. Consider the following code:

section
  variables (n : ) (i : fin n)

  #check (i : fin (n +1))                                  -- ↑i : fin (n +1)
  #reduce (infer_instance : has_coe (fin n) (fin (n +1)))  -- error

  #reduce (i : fin (n +1))                                 -- nat.cast (i.val)
end

I want to cast i from fin n to fin (n +1). This is fine using (i : fin (n +1)).
The #check mention in which I believe it is something to has_coe class so I dig deeper to understand the function behind it, however, it fails to find such an instance. At this point, I am really confused so I change #check to #reduce and get nat.cast (i.val).

My question is that why #reduce successfully find the instance but infer_instance doesn't. Is there another way to cast things without using has_coe/has_lift?

Kevin Buzzard (Aug 11 2019 at 23:52):

What's the definition of nat.cast? Just right click on it in vs code and go to the definition, and it might give some insight into what's going on

Kevin Buzzard (Aug 11 2019 at 23:54):

Oh! Isn't this the function which defines a map from nat to any structure with zero and one and add or something? So maybe the cast is going via nat and isn'ta direct coercion

Mario Carneiro (Aug 12 2019 at 02:02):

There is no direct map from fin n to fin (n+1), so has_coe fails. However has_coe_t probably succeeds and that's what the up arrow actually uses. As kevin says, the actual map goes via nat


Last updated: Dec 20 2023 at 11:08 UTC