Zulip Chat Archive
Stream: new members
Topic: what is LT in `LT.lt.not_lt`?
rzeta0 (Dec 04 2024 at 00:00):
What does the LT
in LT.lt.not_lt
mean?
I read this as a namespace similar to the Nat
namespace under which several lemmas related to natural numbers reside.
What namespace is LT
?
Junyan Xu (Dec 04 2024 at 00:06):
It's a notation typeclass, in particular a structure.
docs#LT.lt is a projection of the structure.
Niels Voss (Dec 04 2024 at 00:24):
It is a namespace, as you guessed, but it was automatically generated when the typeclass LT
was defined. So LT
is both a namespace and a typeclass. (Technically, namespaces aren't "generated", since they are basically just a prefix for an identifier, but in any case the lt
was automatically added to the LT
namespace)
rzeta0 (Dec 04 2024 at 00:34):
What's a type class?
Is it things like LinearOrdered
? If so, what properties define an object in the type class LT
?
This is far outside my comfort zone so feel free to tell me to ignore this question for now.
The reason I pursued it is because the naming convention for lemmas isn't as intuitive or predicable as I had hoped.
Niels Voss (Dec 04 2024 at 01:17):
Type classes are a bit of a complicated subject. Semi-formally, a typeclass is a structure or inductive type that is allowed to appear in [] brackets as arguments to a def
,lemma
,theorem
,etc. and is allowed to appear as the type of an instance
definition. Don't worry if that didn't make sense right now.
Typeclasses basically serve the same role as interface
s from Java and C#, or trait
s in Rust. You can read about them in #tpil
For your specific problem, basically note that mathematicians didn't want to have to reprove the same theorem for Nat and Int and Real if the theorem only used the < symbol. So the same theorem in Mathlib might work for Nat and some other types. So instead of Nat.le_trans
, the theorem might just be named le_trans
.
Kyle Miller (Dec 04 2024 at 01:30):
docs#LT shows that it is a type with an lt
function.
docs#LinearOrder shows that not only does it have lt
, but 15 other fields as well.
Kyle Miller (Dec 04 2024 at 01:34):
(Fun fact @Niels Voss, namespaces actually do have some reality, and an LT
namespace is created at some point. I think Lean keeps track of namespaces for resolving names and giving completions. docs#Lean.Environment.registerNamespace)
Niels Voss (Dec 04 2024 at 01:40):
Oh that's interesting, I didn't know that. This is usually not relevant to the end-user though, right?
Kyle Miller (Dec 04 2024 at 01:42):
I think it's pretty much just an optimization, so that Lean can consult a list of all the namespaces without needing to traverse the complete set of all declarations to compute it.
Jireh Loreaux (Dec 04 2024 at 01:55):
rzeta0 said:
The reason I pursued it is because the naming convention for lemmas isn't as intuitive or predicable as I had hoped.
@rzeta0 please note: the name of this lemma is special. It is not meant to be as natural as you might expect, it's explicitly useful for dot notation. In particular, if you have h : a < b
, then you can write h.not_lt
for a proof of ¬ b < a
.
In fact, if you look at docs#LT.lt.not_lt, you'll see that this is an alias
for the lemma with the proper name: docs#lt_asymm.
Jireh Loreaux (Dec 04 2024 at 01:56):
There's also docs#not_lt_of_lt, which is yet another alias of lt_asymm
.
Johan Commelin (Dec 04 2024 at 05:39):
@rzeta0 Maybe the following also helps to explain the name.
variable (a b : Nat)
#check a < b -- a < b : Prop
set_option pp.notation false
#check a < b -- LT.lt a b : Prop
So a < b
doesn't really fit into the low-level way that Lean thinks about the world: functions applied to other things by juxtaposition, like f x
.
It does fit into a higher-level way that Lean understands, by using a notation system that allows infix operators. So at some point a < b
was introduced as notation for LT.lt a b
, and the latter is an ordinary function application again.
So if you have h : a < b
, then under the hood that means h : LT.lt a b
. And therefore you can use dot-notation:
- lemmas with names of the form
LT.lt.foobar
- that take an argument
(hyp : x < y)
- can be can be called as `h.foobar
- and will have
h
passed as the argumenthyp
.
Just like if you have
def Nat.factorial (n : Nat) : Nat := sorry
Whenever you have a k : Nat
floating around, you can call k.factorial
. Because Lean will inspect the type of k
, and find that it is Nat
. So then it looks for Nat.factorial
, and passes k
as the first argument of type Nat
.
If you write h.not_lt
then Lean inspects the type of h
, finds that it has type LT.lt a b
, and therefore looks for a lemma called LT.lt.not_lt
. Then passes h
as the first argument of type LT.lt _ _
to that lemma.
Mario Carneiro (Dec 05 2024 at 11:11):
Kyle Miller said:
I think it's pretty much just an optimization, so that Lean can consult a list of all the namespaces without needing to traverse the complete set of all declarations to compute it.
not just an optimization, it impacts how open
resolves, as well as whether it will error
Mario Carneiro (Dec 05 2024 at 11:19):
def bar.X := 1
namespace A
section
open foo -- unknown namespace 'foo'
open bar -- resolves to _root_.bar
#check X -- ok
end
namespace foo end foo
namespace bar end bar
section
open foo -- ok
open bar -- resolves to A.bar
#check X -- fail
end
Last updated: May 02 2025 at 03:31 UTC