Zulip Chat Archive

Stream: lean4

Topic: arbitrary is a constant


Kenny Lau (Jan 05 2021 at 21:25):

src/Init/Prelude.lean LL187-197:

class Inhabited (α : Sort u) where
  mk {} :: (default : α)

constant arbitrary [Inhabited α] : α :=
  Inhabited.default

instance : Inhabited (Sort u) where
  default := PUnit

instance (α : Sort u) {β : Sort v} [Inhabited β] : Inhabited (α  β) where
  default := fun _ => arbitrary

Kenny Lau (Jan 05 2021 at 21:25):

Why is arbitrary a constant? Won't this cause the definition to be inaccessible?

Kenny Lau (Jan 05 2021 at 21:25):

and why does the Inhabited (α → β) instance use the opaque arbitrary?

Kenny Lau (Jan 05 2021 at 21:26):

or am I completely misunderstanding how constant works?

Leonardo de Moura (Jan 05 2021 at 21:26):

Kenny Lau said:

Why is arbitrary a constant? Won't this cause the definition to be inaccessible?

It is to make sure your proof doesn't depend on the actual value of arbitrary.

Kenny Lau (Jan 05 2021 at 21:28):

So the following code I wrote is not advisable?

instance instSortInhabited' : Inhabited (Inhabited.default : Sort u) := PUnit.unit

Leonardo de Moura (Jan 05 2021 at 21:28):

Kenny Lau said:

or am I completely misunderstanding how constant works?

A constant should be viewed as an opaque definition. It is like Lean 3 [irreducible], but it is enforced by the Kernel too.

Leonardo de Moura (Jan 05 2021 at 21:30):

So the following code I wrote is not advisable?

Not sure what you are trying to do. Happy to chat tomorrow on Zoom or gather.com :)

Kenny Lau (Jan 05 2021 at 21:33):

I was porting mathlib logic.basic whose L53 reads:

instance sort.inhabited' : inhabited (default (Sort*)) := punit.star

Leonardo de Moura (Jan 05 2021 at 21:40):

Not sure where people use this instance, but the code you posted before is a faithful translation of L53.

Mario Carneiro (Jan 06 2021 at 00:53):

I think we need

instance (α : Sort u) {β : Sort v} [Inhabited β] : Inhabited (α  β) where
  default := fun _ => Inhabited.default

instead of arbitrary, because there are a decent number of uses of the inhabited instance that go via default instead of arbitrary, and expect it to be defined as the constant function (for example, we need the zero of the function space to be the constant function 0 and not some arbitrary thing). With the arbitrary definition on function types we get that

example : (Inhabited.default : Nat) = 0 := rfl -- this works
example : (Inhabited.default : Nat  Nat) 0 = 0 := rfl -- this fails

Mario Carneiro (Jan 06 2021 at 00:57):

(In fact, I think that arbitrary is almost never used in mathlib. In most uses we aren't assuming that the value doesn't matter, although it seems fine to opt into this by using arbitrary explicitly.)

Johan Commelin (Jan 06 2021 at 05:27):

arguably we are giving it different semantics... so maybe we can distinguish between arbitrary and default.

Mario Carneiro (Jan 06 2021 at 09:36):

As in having a separate typeclass for supplying arbitrary vs default? Perhaps we should call the former nonempty...

Eric Wieser (Jan 06 2021 at 12:35):

Isn't one typeclass enough, combined with the rule "never implement inhabited using arbitrary"?

Eric Wieser (Jan 06 2021 at 12:36):

Because then you can always fully unfold default, and it doesn't matter that arbitrary is implemented with default because you never unfold it

Gabriel Ebner (Jan 06 2021 at 12:51):

Maybe also add export Inhabited (default)


Last updated: Dec 20 2023 at 11:08 UTC