Zulip Chat Archive
Stream: general
Topic: What to do with empty?
provemeifyoucan (May 06 2024 at 09:22):
Hi. Why does this code not work?
def wtf : (b:Bool) -> if b then Unit else Empty
| true => ()
| false => by contradiction
Mitchell Lee (May 06 2024 at 09:28):
It would be a contradiction if you could prove False, but it isn't a contradiction to have a boolean value that's equal to false.
Yaël Dillies (May 06 2024 at 09:29):
I think you meant something like
def notWTF : (b:Bool) -> b -> if b then Unit else Empty
provemeifyoucan (May 06 2024 at 12:03):
Yaël Dillies said:
I think you meant something like
def notWTF : (b:Bool) -> b -> if b then Unit else Empty
Why is it necessary to pass b twice? In the original example, the goal becomes Empty too. What should I do in such cases? Passing the argument twice doesn't look like the cleanest solution possible...
Kim Morrison (May 06 2024 at 12:14):
This is not passing b
twice. It is passing a boolean and then a proof that the boolean equals true
.
Kim Morrison (May 06 2024 at 12:15):
If the boolean is false
, there is no way you are going to construct a term of type Empty
.
Eric Wieser (May 06 2024 at 12:17):
Perhaps it's more clear if you write it as
def notWTF : (b : Bool) -> (h : b) -> if b then Unit else Empty
which means exactly the same thing as what Yaël Dillies wrote
provemeifyoucan (May 06 2024 at 12:21):
Eric Wieser said:
Perhaps it's more clear if you write it as
def notWTF : (b : Bool) -> (h : b) -> if b then Unit else Empty
which means exactly the same thing as what Yaël Dillies wrote
Now I am even more confused. How is it legal to do h : b
? b is already an instance of type Bool, right? Still not clear what I have to do when the goal of some expression evaluates to an empty type.
Johan Commelin (May 06 2024 at 12:24):
provemeifyoucan said:
Still not clear what I have to do when the goal of some expression evaluates to an empty type.
Find a term of the empty type in your local context. If there is none, construct one using stuff from your local context.
Eric Wieser (May 06 2024 at 12:24):
How is it legal to do
h : b
?
h : b
actually elaborates as h : b = true
provemeifyoucan (May 06 2024 at 12:29):
Johan Commelin said:
provemeifyoucan said:
Still not clear what I have to do when the goal of some expression evaluates to an empty type.
Find a term of the empty type in your local context. If there is none, construct one using stuff from your local context.
In my local context, I got just b being pattern-matched to true and false with the goals in arms being respectively Unit and Empty types. I supposed I wouldn't need anything else to state some trivia...
Eric Wieser (May 06 2024 at 12:33):
Johan missed one thing from his list. "If you can't construct one, then you need to backtrack and undo a previous wrong turn". Here, your pattern match was fine, but your original definition is nonsense.
provemeifyoucan (May 06 2024 at 12:33):
Eric Wieser said:
Johan missed one thing from his list. "If you can't construct one, then you need to backtrack and undo a previous wrong turn". Here, your pattern match was fine, but your original definition is nonsense.
Nonesense how?
Johan Commelin (May 06 2024 at 12:33):
If (and only if) you are still trying to make this work
def wtf : (b:Bool) -> if b then Unit else Empty
| true => ()
| false => by contradiction
then I suggest that you first try to understand why
def zero? : (n:Nat) -> if n = 0 then Unit else Empty
| 0 => ()
| n+1 => by contradiction
doesn't work
Eric Wieser (May 06 2024 at 12:34):
Nonsense in this sense:
def wtf : (b:Bool) -> if b then Unit else Empty := sorry
-- if the `sorry` above can be filled, then false is true
example : False := (wtf false).elim
provemeifyoucan (May 06 2024 at 12:41):
Johan Commelin said:
If (and only if) you are still trying to make this work
def wtf : (b:Bool) -> if b then Unit else Empty | true => () | false => by contradiction
then I suggest that you first try to understand why
def zero? : (n:Nat) -> if n = 0 then Unit else Empty | 0 => () | n+1 => by contradiction
doesn't work
In case you didnt notice I asking why it doesnt work, which implies that I would like to have an answer to this.
Anyway, since you just said the case with zero? doesn't work it makes me question usefulness of lean at this point.
Johan Commelin (May 06 2024 at 12:42):
Do you understand why
def oops : Empty := by contradiction
doesn't work?
Johan Commelin (May 06 2024 at 12:42):
It isn't too much of an exaggeration to say that Lean is useful precisely because examples like yours don't work.
provemeifyoucan (May 06 2024 at 12:43):
Eric Wieser said:
Nonsense in this sense:
def wtf : (b:Bool) -> if b then Unit else Empty := sorry -- if the `sorry` above can be filled, then false is true example : False := (wtf false).elim
What would make it true? I expected that any attempt to pattern match empty type would just lead to nowhere.
Eric Wieser (May 06 2024 at 12:44):
That's the opposite of the case: pattern matching an empty type leads to everywhere!
def foo (e : Empty) : AProofOfAnyMilleniumProblem := nomatch e
Johan Commelin (May 06 2024 at 12:44):
You are trying to define something of type Empty
. I think it shouldn't be surprising that it is not possible.
provemeifyoucan (May 06 2024 at 12:45):
Johan Commelin said:
Do you understand why
def oops : Empty := by contradiction
doesn't work?
I feel like it should. Because an attempt to use it would be never possible.
Like nothing compromises things like this
def f : Empty -> Type
| ...
Yaël Dillies (May 06 2024 at 12:46):
Maybe you're confused by the (b : Bool) →
notation? This is exactly the same as your original example, but using ∀
:
def wtf : ∀ b : Bool, if b then Unit else Empty
| true => ()
| false => by contradiction
Eric Wieser (May 06 2024 at 12:47):
provemeifyoucan said:
Like nothing compromises things like this
def f : Empty -> Type | ...
"given a thing that can't exist, produce X", is very different to "produce a thing that can't exist". There is a very fundamental difference between the left and right of ->
.
Yaël Dillies (May 06 2024 at 12:47):
So wtf
is the collection for every Boolean b
of an element of type if b then Unit else Empty
. Equivalently, it's the data of an element of Unit
and of an element of Empty
.
provemeifyoucan (May 06 2024 at 12:48):
Eric Wieser said:
provemeifyoucan said:
Like nothing compromises things like this
def f : Empty -> Type | ...
"given a thing that can't exist, produce X", is very different to "produce a thing that can't exist". There is a very fundamental difference between the left and right of
->
.
I meant that inexistence of such functions woulndt suddenly be allowed
Johan Commelin (May 06 2024 at 12:50):
provemeifyoucan said:
Johan Commelin said:
Do you understand why
def oops : Empty := by contradiction
doesn't work?
I feel like it should.
But that means that oops
will be an element of Empty
. But Empty
is empty! It can't have any elements. That's its nature!
So really, it is a fantastic feature of Lean that you cannot complete the line
def oops : Empty :=
Johan Commelin (May 06 2024 at 12:51):
Btw, there certainly is a function Empty -> Type
. Lean is perfectly happy with that. For every element of Empty
, you need to tell Lean to which type you want to send it. But because Empty
doesn't have any elements, you are done before you even started.
provemeifyoucan (May 06 2024 at 12:51):
Yaël Dillies said:
Maybe you're confused by the
(b : Bool) →
notation? This is exactly the same as your original example, but using∀
:def wtf : ∀ b : Bool, if b then Unit else Empty | true => () | false => by contradiction
I think I want confused by notation, as long as (a:T) -> expr a means a dependent function. Only about what I should do when the goal is empty type. Like... what should I write there? How just pattern matching leading to an impossible case is not enough for contradiction to work?
Kyle Miller (May 06 2024 at 12:52):
"you can use emptiness, but you cannot create emptiness"
Eric Wieser (May 06 2024 at 12:52):
Contradiction requires impossible assumptions, not impossible conclusions
provemeifyoucan (May 06 2024 at 12:52):
Johan Commelin said:
provemeifyoucan said:
Johan Commelin said:
Do you understand why
def oops : Empty := by contradiction
doesn't work?
I feel like it should.
But that means that
oops
will be an element ofEmpty
. ButEmpty
is empty! It can't have any elements. That's its nature!So really, it is a fantastic feature of Lean that you cannot complete the line
def oops : Empty :=
Nothing in this statement add any elements to empty
Johan Commelin (May 06 2024 at 12:53):
Everything in def oops : Empty :=
is adding an element to Empty
!!!
Kyle Miller (May 06 2024 at 12:55):
If you could replace this sorry
with something, that would mean you could prove False
, which would mean that Lean's logic is inconsistent:
def oops : Empty := sorry
example : False := by
have := oops
contradiction
provemeifyoucan (May 06 2024 at 12:56):
Kyle Miller said:
"you can use emptiness, but you cannot create emptiness"
Well then, why is this code legal?
def notWTF : (b : Bool) -> (h : b) -> if b then Unit else Empty
provemeifyoucan (May 06 2024 at 12:57):
Kyle Miller said:
If you could replace this
sorry
with something, that would mean you could proveFalse
, which would mean that Lean's logic is inconsistent:def oops : Empty := sorry example : False := by have := oops contradiction
I thought sorry in lean mean 'this definition has no computational content' exactly like Empty
Johan Commelin (May 06 2024 at 12:57):
Because in the false branch you have assumed something that is false.
Kyle Miller (May 06 2024 at 12:57):
That's shorthand for
def notWTF : (b : Bool) -> (h : b = true) -> if b then Unit else Empty
and when b
is false, then the second argument is false = true
, which is empty, and from that emptiness you can "produce" a value of Empty
.
Johan Commelin (May 06 2024 at 12:58):
@provemeifyoucan No, sorry
means "just assume this can be done, stop complaining".
Yaël Dillies (May 06 2024 at 12:58):
Eric Wieser said:
Contradiction requires impossible assumptions, not impossible conclusions
You're missing the point, I believe. provemeifyoucan is confused about the fact that the assumptions are not impossible, not the conclusions
Johan Commelin (May 06 2024 at 12:58):
So sorry
makes Lean very unsafe.
Kyle Miller (May 06 2024 at 12:59):
sorry
is the axiom is that everything is true, which we use to fill in unfinished proofs or values, but its use is recorded and warnings are logged so that we can make sure they're all dealt with eventually
Johan Commelin (May 06 2024 at 12:59):
sorry
is not allowed to be used in mathlib. And in general, it shouldn't appear in "end products".
Kyle Miller (May 06 2024 at 13:01):
Well then, why is this code legal?
Here's it written as a tactic proof you can step through in case it makes it clearer.
def notWTF : (b : Bool) -> (h : b = true) -> if b then Unit else Empty := by
intro b h
cases b
· contradiction -- h : false = true is a contradiction
· exact ()
Patrick Stevens (May 06 2024 at 15:11):
I thought
sorry
in lean mean 'this definition has no computational content' exactly like Empty
That is instead indicated by the keyword noncomputable
, by the way.
provemeifyoucan (May 08 2024 at 19:21):
Johan Commelin said:
It isn't too much of an exaggeration to say that Lean is useful precisely because examples like yours don't work.
This works and it is what I wanted to do.
def Empty2 : Type := Empty -> Unit
def impossible : Empty -> Unit := nofun
def n3 : (n:Nat) -> match n with | .zero => Empty2 | .succ _ => Nat
| n@(.succ _) => n
| .zero => impossible
#eval n3 1 -- works
-- #eval n3 0 -- doesnt
Is lean still useful?
provemeifyoucan (May 08 2024 at 19:28):
provemeifyoucan said:
Johan Commelin said:
It isn't too much of an exaggeration to say that Lean is useful precisely because examples like yours don't work.
This works and it is what I wanted to do.
def Empty2 : Type := Empty -> Unit def impossible : Empty -> Unit := nofun def n3 : (n:Nat) -> match n with | .zero => Empty2 | .succ _ => Nat | n@(.succ _) => n | .zero => impossible #eval n3 1 -- works -- #eval n3 0 -- doesnt
Is lean still useful?
The stranger thing is that it is possible to define impossible
as
def impossible2 : Empty -> Unit := fun _ => ()
Which is the same thing. Why is it called nofun haha? I have lots so far!
Yury G. Kudryashov (May 08 2024 at 19:31):
You're just using a type that doesn't support eval for the type of n3 0
. It's still a valid expression.
provemeifyoucan (May 08 2024 at 19:31):
Yury G. Kudryashov said:
You're just using a type that doesn't support eval for the type of
n3 0
. It's still a valid expression.
Thats the point!
Johan Commelin (May 08 2024 at 19:32):
Why are you giving Empty2
that name?
Johan Commelin (May 08 2024 at 19:33):
And also, why are you giving impossible
that name?
Johan Commelin (May 08 2024 at 19:34):
Is lean still useful?
Certainly!
Henrik Böving (May 08 2024 at 19:39):
@provemeifyoucan what is it that you are actually after here? An understanding of how empty types work?
Kyle Miller (May 08 2024 at 20:34):
I'm confused about Empty2
being called that. The cardinality of is always , it's not empty.
Kyle Miller (May 08 2024 at 20:35):
(impossible
is that single function in this set of functions, at least when )
provemeifyoucan (May 09 2024 at 02:10):
Henrik Böving said:
provemeifyoucan what is it that you are actually after here? An understanding of how empty types work?
You apparently cant read: I wanted a tactic that closes goals of an empty type. I found one.
provemeifyoucan (May 09 2024 at 02:14):
Kyle Miller said:
I'm confused about
Empty2
being called that. The cardinality of is always , it's not empty.
What? Are you trying to make up an excuse or smth?
Kyle Miller (May 09 2024 at 02:52):
Make up an excuse for what?
The type Empty2
is certainly not empty. It's well-known that when the domain set is empty, there exists a function. (I just linked to Planet Math because it came up to find a quick reference.)
The nofun
function, despite its name, is actually a function. It's called that because there are no cases to consider when making a function whose domain isempty, not that there are no functions.
Kyle Miller (May 09 2024 at 02:54):
You apparently cant read
We try to be a bit more civil that that here. Please assume Henrik is asking his question in good faith. I too am wondering what the context is for your question, what you were doing to end up with the question about trying to construct a function of type (b:Bool) -> if b then Unit else Empty
.
provemeifyoucan (May 09 2024 at 03:35):
Kyle Miller said:
The type
Empty2
is certainly not empty. It's well-known that when the domain set is empty, there exists a function. (I just linked to Planet Math because it came up to find a quick reference.)
His argument relies on the fact that n^0 = 1. This doesn't look convincing.
That type is empty. Intuitively because you can't use it to compute anything.
Andrew Yang (May 09 2024 at 03:44):
Maybe you are more familiar with set-theoretic foundations? Under such a foundation, a function is a subset such that . Now if is empty, it is a fun exercise to verify that indeed satisfies the condition, and thus defines a function . This is called the empty function.
provemeifyoucan (May 09 2024 at 03:54):
Andrew Yang said:
Maybe you are more familiar with set-theoretic foundations? Under such a foundation, a function is a subset such that . Now if is empty, it is a fun exercise to verify that indeed satisfies the condition, and thus defines a function . This is called the empty function.
I read the last part as . Which means... it is not inhabited aka empty function
Johan Commelin (May 09 2024 at 04:14):
@provemeifyoucan Please read #butterfly.
Also, if you can define a term of type False
then you show that lean is inconsistent. Can you use impossible
to do that?
provemeifyoucan (May 09 2024 at 04:16):
Johan Commelin said:
provemeifyoucan Please read #butterfly.
Also, if you can define a term of typeFalse
then you show that lean is inconsistent. Can you useimpossible
to do that?
I was hoping some of you would do it! To me, inconsistency is the ability to perform bad computations. And computation that doesn't happen can't be bad.
And so far, what I did does not look like it can lead to inconsistencies.
Johan Commelin (May 09 2024 at 04:18):
Ok, then I suggest we stop this discussion. Nobody here is surprised by your impossible
and Empty2
. Only by the names that you chose.
provemeifyoucan (May 09 2024 at 04:20):
Johan Commelin said:
Ok, then I suggest we stop this discussion. Nobody here is surprised by your
impossible
andEmpty2
. Only by the names that you chose.
Nice of you to assume nobody else may be interested in this, because of some dogmatic belief that hold you back from accepting this.
Ive shown the term that closes empty type, btw.
Also, please read #butterfly
Johan Commelin (May 09 2024 at 04:24):
You can't simply call a random type Empty2
, define a term of it, and declare victory.
Just like you can't call a random statement "Riemann Hypothesis 2", prove it, and collect 1M bucks.
Johan Commelin (May 09 2024 at 04:25):
If you want to "show the term that closes empty types" then your approach must close goals of type Empty
. Not just Empty2
.
provemeifyoucan (May 09 2024 at 04:26):
Johan Commelin said:
You can't simply call a random type
Empty2
, define a term of it, and declare victory.
Just like you can't call a random statement "Riemann Hypothesis 2", prove it, and collect 1M bucks.
Its not a random type. Its an empty type.
Dont write anymore in this thread, please.
Johan Commelin (May 09 2024 at 04:27):
Fwiw, your impossible
shows up in dozens of places in mathlib and other projects. It is incredibly useful.
Johan Commelin (May 09 2024 at 04:28):
We just don't give it that name.
provemeifyoucan (May 09 2024 at 04:28):
Johan Commelin said:
Fwiw, your
impossible
shows up in dozens of places in mathlib and other projects. It is incredibly useful.
Link please
Johan Commelin (May 09 2024 at 04:30):
https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#Empty.elim
provemeifyoucan (May 09 2024 at 04:40):
Johan Commelin said:
https://leanprover-community.github.io/mathlib4_docs/Init/Core.html#Empty.elim
Nice! Lean can close goals which are empty types.
It would be great to add one convenience tactic to deal with the following
def imp : Empty := by impossible
Thomas Murrills (May 09 2024 at 04:41):
Textual communication can be tricky, as we lose a lot of information about tone and intention (at least, I feel this way); but @provemeifyoucan please rest assured that while people might be repeatedly saying you’re incorrect here, they are all very nice people and are earnestly trying to help (also, they know what they’re talking about!).
Let me try to pinpoint a potential source of confusion. Are you under the impression that a term of type Empty → Unit
closes a goal of type Empty
? If so, this is the issue, because that is not the case! (Happy to explain why further, but first let me see if my guess is correct.)
Johan Commelin (May 09 2024 at 04:44):
@provemeifyoucan I will write that tactic if you tell me exactly which term should be generated by by impossible
(and it typechecks).
provemeifyoucan (May 09 2024 at 04:44):
Thomas Murrills said:
Are you under the impression that a term of type
Empty → Unit
closes a goal of typeEmpty
? If so, this is the issue, because that is not the case!
Empty → Unit
is an empty type and when it's a goal there is a term that closes it, yes.
Johan Commelin (May 09 2024 at 04:46):
I will only believe that a type is empty if you implement an instance of IsEmpty
for it.
Thomas Murrills (May 09 2024 at 04:47):
provemeifyoucan said:
Thomas Murrills said:
Are you under the impression that a term of type
Empty → Unit
closes a goal of typeEmpty
? If so, this is the issue, because that is not the case!
Empty → Unit
is an empty type and when it's a goal there is a term that closes it, yes.
Why do you believe Empty → Unit
is empty?
provemeifyoucan (May 09 2024 at 04:53):
Thomas Murrills said:
provemeifyoucan said:
Thomas Murrills said:
Are you under the impression that a term of type
Empty → Unit
closes a goal of typeEmpty
? If so, this is the issue, because that is not the case!
Empty → Unit
is an empty type and when it's a goal there is a term that closes it, yes.Why do you believe
Empty → Unit
is empty?
I explained it here
Jireh Loreaux (May 09 2024 at 04:56):
Empty → Unit
is not an empty type, as others have said. What evidence would it take for you believe it is not empty? (Note: Johan has explained what evidence it would take for him to believe it is empty, an instance of IsEmpty
for it.)
Thomas Murrills (May 09 2024 at 05:00):
Hmm, I’m not sure I follow your explanation @provemeifyoucan. There is a unique function for any set ; do you not agree with that? If not, let me ask you: what is your definition of a function, either in terms of sets or types?
provemeifyoucan (May 09 2024 at 05:08):
Erhm, is lean okay?
Screenshot_20240509_110709.png
Screenshot_20240509_110714.png
Jireh Loreaux (May 09 2024 at 05:17):
Yep, that makes sense. You are trying to tell Lean that there are no matches for i : Empty -> Unit
, but there is one!
If you delete line 81 (and leave line 82), you will have constructed the function.
provemeifyoucan (May 09 2024 at 05:26):
Jireh Loreaux said:
Yep, that makes sense. You are trying to tell Lean that there are no matches for
i : Empty -> Unit
, but there is one!If you delete line 81 (and leave line 82), you will have constructed the function.
Any idea about what I can write here?
def oof (T:Type) : T -> Empty := fun _ => sorry
def empty_fun_b : Empty -> (Empty -> Unit) := Empty.elim
def empty_fun_f : (Empty -> Unit) -> Empty := oof _
Jireh Loreaux (May 09 2024 at 05:41):
It's impossible to write anything there (for empty_fun_f
) because the domain, namely Empty -> Unit
has a single element (which is the function fun _ => ()
), whereas the codomain, namely Empty
, has no elements.
provemeifyoucan (May 09 2024 at 05:42):
Does it mean I cannot show that there are no function from any set to empty set?
Jireh Loreaux (May 09 2024 at 05:43):
It's impossible to construct oof T
unless you also assume T
is empty.
provemeifyoucan (May 09 2024 at 05:43):
Jireh Loreaux said:
It's impossible to construct
oof T
unless you also assumeT
is empty.
Does it mean I cannot show that there are no functions from any set to empty set?
Jireh Loreaux (May 09 2024 at 05:43):
provemeifyoucan said:
Does it mean I cannot show that there are no function from any set to empty set?
Of course, unless the set for the domain is empty.
provemeifyoucan (May 09 2024 at 05:45):
Jireh Loreaux said:
provemeifyoucan said:
Does it mean I cannot show that there are no function from any set to empty set?
Of course, unless the set for the domain is empty.
Leans logic is weak then
Jireh Loreaux (May 09 2024 at 05:46):
??? It's weak because it doesn't allow you to build things that don't exist? No, that's what makes it useful. If you could build things that don't exist, then you could prove False
.
provemeifyoucan (May 09 2024 at 05:47):
provemeifyoucan said:
Jireh Loreaux said:
It's impossible to construct
oof T
unless you also assumeT
is empty.Does it mean I cannot show that there are no functions from any set to empty set?
Yeah, just pluging in nofun for sorry gives again this error of missing _ case.
Jireh Loreaux (May 09 2024 at 05:50):
Sure. nofun
is for when the domain is an empty inductive type.
provemeifyoucan (May 09 2024 at 05:50):
no wait its actually this
Screenshot_20240509_115559.png
provemeifyoucan (May 09 2024 at 05:50):
provemeifyoucan said:
no wait its actually this
Screenshot_20240509_115007.png
Zero missing cases
Jireh Loreaux (May 09 2024 at 05:51):
No, it's not zero missing cases, it's that T
is an unspecified type, so Lean cannot give you the cases corresponding to its inductive constructors.
provemeifyoucan (May 09 2024 at 05:52):
A constructorless type!! I wonder what that means.....
Jireh Loreaux (May 09 2024 at 05:53):
It's not constructorless necessarily, it's unspecified (i.e., arbitrary).
Jireh Loreaux (May 09 2024 at 05:54):
For example, T
could be Nat
or Bool
, or ... whatever.
Jireh Loreaux (May 09 2024 at 05:57):
(and because I couldn't tell whether or not your comment above was sarcastic: there are constructorless types, such as False
or Empty
)
provemeifyoucan (May 09 2024 at 06:10):
Jireh Loreaux said:
provemeifyoucan said:
Does it mean I cannot show that there are no function from any set to empty set?
Of course, unless the set for the domain is empty.
So if we let function be products i.e.
it is possible to represent function A -> Empty
and Empty -> A
as and respectively.
As product they can be written like this
and
If we apply rule that product of an empty set with anything else is an empty set we get an empty set which means
because
And you are trying to convince me that
Do you see the problem?
Yury G. Kudryashov (May 09 2024 at 06:17):
A function is not the product. It's a subset $$s \subst A \times B$$ such that . In case of a function , you get which is true, because the empty set has no elements. For with nonempty , you get , which can't be true: take (this is possible since is nonempty); then we get which is false, because has no elements.
Jireh Loreaux (May 09 2024 at 06:18):
Sure, we can work in set-theoretic terminolgy. Functions are not products. They are subsets of products with the property that for every element of the domain, there is a unique element of the codomain such that the pair is in the subset.
So, a function from Empty -> Unit
would be a subset of with that property, and the empty set suffices for this. Crucially, the property is satisfied because the domain is empty.
However, a function from Unit -> Empty
would be a subset of with the property, but no such subset exists. Indeed the only subset is the empty set, but there is no pair of the form for some b in the empty set.
Eric Wieser (May 09 2024 at 07:08):
Do you see the problem?
You can actually use Lean to prove that
So if we let function be products i.e.
is the problem:
import Mathlib
/-- Functions are not products (if they were, we could prove `False`) -/
example (h : ∀ α β : Type, (α → β) ≃ (α × β)) : False := by
-- counterexample: use types with two and three elements
specialize h (α := Fin 2) (β := Fin 3)
-- count them
replace h := Fintype.card_congr h
-- the function has 9 elements, but the product only 6
have : 9 = 6 := by simpa only [Fintype.card_pi, Fintype.card_fin] using h
-- this is nonsense
cases this
Patrick Stevens (May 09 2024 at 08:14):
Meta-point: if you want to be assured that the weight of mathematical opinion is with the statement "there's only one domain which admits a function to the empty set, namely the empty set itself with its identity", the search term you can easily verify with Google is that the empty set is a strict initial object in the category of sets. Whether you believe the weight of mathematical opinion is up to you, but you should expect mathematicians to go with the standard!
provemeifyoucan (May 10 2024 at 07:11):
Eric Wieser said:
Do you see the problem?
You can actually use Lean to prove that
So if we let function be products i.e.
is the problem:
import Mathlib /-- Functions are not products (if they were, we could prove `False`) -/ example (h : ∀ α β : Type, (α → β) ≃ (α × β)) : False := by -- counterexample: use types with two and three elements specialize h (α := Fin 2) (β := Fin 3) -- count them replace h := Fintype.card_congr h -- the function has 9 elements, but the product only 6 have : 9 = 6 := by simpa only [Fintype.card_pi, Fintype.card_fin] using h -- this is nonsense cases this
I was thinking about this tbh
def fr : (A × (A -> B)) -> A × B
| (a , f) => (a , f a)
def bw : (A × B) -> (A × (A -> B))
| (a, b) => (a, fun _ => b)
def y : (Empty × (Empty -> Unit)) -> (Empty × Unit) := by
intro m
have (a, _) := m
contradiction
def y2 : (Empty × Unit) -> (Empty × (Empty -> Unit)) := by
intro m
have (a, _) := m
contradiction
Should I say that they are inhabited by contradiction?
provemeifyoucan (May 10 2024 at 07:22):
If I just swap arguments I can no longer write code that means same thing
def y7 : (Unit × (Unit -> Empty)) -> (Unit × Empty) := by
sorry
def y8 : (Unit × Empty) -> (Unit × (Unit -> Empty)) := by
intro m
have (_, _) := m
contradiction
Does this mean A * B != B * A in lean?
Yaël Dillies (May 10 2024 at 07:26):
A × B
is indeed not the same thing as B × A
, if this is what you mean.
provemeifyoucan (May 10 2024 at 07:28):
Yaël Dillies said:
A × B
is indeed not the same thing asB × A
, if this is what you mean.
def swap : (A × B) -> (B × A) | (a,b) => (b,a)
def swap_same : (a: A × B) -> a = swap (swap a) := by
intros a
rfl
WDYM?
Yaël Dillies (May 10 2024 at 07:30):
I am trying to interpret your "Does this mean A * B != B * A in lean?" :shrug: A × B
and B × A
are in bijection but they are not "the same".
provemeifyoucan (May 10 2024 at 07:32):
Yaël Dillies said:
I am trying to interpret your "Does this mean A * B != B * A in lean?" :shrug:
A × B
andB × A
are in bijection but they are not "the same".
Hold on, I am trying to do
def same : (a: A × B) -> a = swap (swap a)
at the moment
Yaël Dillies (May 10 2024 at 07:33):
provemeifyoucan (May 10 2024 at 07:39):
So (Empty × (Empty -> Unit)) -> (Empty × Unit)
should be same as (Unit × (Unit -> Empty)) -> (Unit × Empty)
What yall think?
Yaël Dillies (May 10 2024 at 07:40):
If by "the same" you mean "in bijection", then yes
provemeifyoucan (May 10 2024 at 07:41):
Yaël Dillies said:
If by "the same" you mean "in bijection", then yes
So it is an empty type then
provemeifyoucan (May 10 2024 at 07:43):
How can I show that Unit -> Empty
is an empty type in lean?
Yaël Dillies (May 10 2024 at 07:44):
example : IsEmpty (Unit → Empty) where
false f := by cases f ()
Marcus Rossel (May 10 2024 at 08:12):
Side note: Your y7
from above can be implemented:
def y7 : (Unit × (Unit -> Empty)) -> (Unit × Empty) :=
fun (u, f) => (u, f u)
provemeifyoucan (May 10 2024 at 08:52):
Marcus Rossel said:
Side note: Your
y7
from above can be implemented:def y7 : (Unit × (Unit -> Empty)) -> (Unit × Empty) := fun (u, f) => (u, f u)
Now we only need to fill this blank in the way I did for y8
to show something really interesting
def empty : Unit → Empty := sorry
Eric Wieser (May 10 2024 at 09:12):
But Yael proved that blank is impossible to fill above
provemeifyoucan (May 10 2024 at 09:13):
Eric Wieser said:
But Yael proved that blank is impossible to fill above
Maybe there's some tactic I don't know about :laughing:
Damiano Testa (May 10 2024 at 09:20):
There is one: sorry
.
Damiano Testa (May 10 2024 at 11:51):
provemeifyoucan said:
Yaël Dillies said:
If by "the same" you mean "in bijection", then yes
So it is an empty type then
I am not sure what you mean when you say "empty type", but this is definitely a different notion that what most people in this chat probably think:
import Mathlib.Logic.IsEmpty
example : Nonempty ((Empty × (Empty → Unit)) → (Empty × Unit)) := by simpa using instIsEmptyEmpty
example : Subsingleton ((Empty × (Empty → Unit)) → (Empty × Unit)) := instSubsingletonForall
example : Nonempty ((Unit × (Unit → Empty)) → (Unit × Empty)) := by simpa using instIsEmptyEmpty
example : Subsingleton ((Unit × (Unit → Empty)) → (Unit × Empty)) := instSubsingletonForall
Patrick Stevens (May 10 2024 at 12:32):
If you can fill in the blank in def empty : Unit -> Empty := sorry
, then you can prove literally any mathematical statement. You can always construct something of type Unit
; so every statement (regardless of whether it's true) can be proved by "let x : False := empty(); contradiction
" (which is pseudocode, sorry, I don't have mathlib or a Lean compiler in my head). So you'd better hope that you can't fill in that blank, because once you've done that, we need to find a different logic that lets us prove less stuff!
Yury G. Kudryashov (May 10 2024 at 14:49):
provemeifyoucan said:
So
(Empty × (Empty -> Unit)) -> (Empty × Unit)
should be same as(Unit × (Unit -> Empty)) -> (Unit × Empty)
What yall think?
Both types are singletons:
example :
((Empty × (Empty -> Unit)) -> (Empty × Unit)) ≃ ((Unit × (Unit -> Empty)) -> (Unit × Empty)) :=
Equiv.equivOfUnique _ _
Yury G. Kudryashov (May 10 2024 at 14:51):
In more details, Empty × (Empty -> Unit)
, Empty × Unit
, Unit × (Unit -> Empty)
, and Unit × Empty
are all empty types, and there is a unique function from an empty type to any other type (IsEmpty.elim
).
Thomas Murrills (May 11 2024 at 18:43):
It’s perhaps worth noting explicitly here that, in terms of sets, the set of all functions from to which I’ll denote (analogous to the type A → B
) is not a subset of , but a subset of (since each function is a subset of ).
And since is singleton (namely, , and so always contains exactly one element, namely ), you’ve always got at least one candidate function (the empty set) when considering and .
To find out which elements of are actually functions, we filter out using the criterion Yury mentioned earlier. Importantly, this criterion is asymmetric in and . So in the generic case, we filter out meaningfully different subsets (i.e. not related by ) in when compared to .
The empty set (recall that it’s always a candidate function, i.e. for any ) fails to meet the criteria of “actually being a function” in the case exactly when is nonempty.
In the case of , the empty set always does meet the criteria of being a function, and, since is the unique such element, is always singleton.
So to sum up, the point here is that while you are correct that
- the function type sticks a in front, which always grants us at least one candidate element of (as for any )
- the function criterion is asymmetric, so different elements will be filtered out as “non-functions” depending on whether we’re looking at or . So may wind up empty by filtering out the empty function while may not.
(As an example, to prove to yourself that in general has a different size than , take and to have elements. You’ll see there are elements of but only one element of . It’s not a stretch for to be reduced to 0 elements while has 1 element!)
Do you have any specific objections to any part of this? Also happy to clarify anything. (In any case this was fun to type out! :) )
Last updated: May 02 2025 at 03:31 UTC