Zulip Chat Archive
Stream: new members
Topic: Some basic questions
sarahzrf (Jan 14 2024 at 03:47):
I'm working through Glimpse of Lean and I was a little surprised to see that this apparently works with the by
removed:
image.png
sarahzrf (Jan 14 2024 at 03:48):
I had assumed so far that by
is how you embed a tactic script into a term, akin to ltac:
in coq, but evidently not?
David Renshaw (Jan 14 2024 at 03:49):
The calc
syntax works both in term mode and in tactic mode.
sarahzrf (Jan 14 2024 at 03:49):
Ahh
sarahzrf (Jan 14 2024 at 03:49):
So if I put a rw
there instead, it would syntax error at me?
sarahzrf (Jan 14 2024 at 03:51):
cool, makes sense
sarahzrf (Jan 16 2024 at 20:12):
How does subgoal focusing work?
sarahzrf (Jan 16 2024 at 20:13):
I'm working thru Glimpse of Lean; it just had me use apply
on something with two hypotheses, and it told me to just prove each of them one after another inline
sarahzrf (Jan 16 2024 at 20:13):
in coq i would be able to use bullets to focus on them one by one, but lean is yelling at me if i try to use a bullet
sarahzrf (Jan 16 2024 at 20:14):
What exactly does a bullet do in lean, then, and how do I organize a proof after applying something with multiple hypotheses, if not with bullets?
Kyle Miller (Jan 16 2024 at 20:15):
You can use ·
for focusing on goals in Lean. Be sure it's the correct dot, there are a number of unicode variants. This one is \.
in VS Code.
sarahzrf (Jan 16 2024 at 20:16):
oh wait i see the problem
Kyle Miller (Jan 16 2024 at 20:16):
There's also using
next =>
tac1
tac2
for focusing. It's the same, but next
lets you name inaccessible variables at the same time.
sarahzrf (Jan 16 2024 at 20:16):
i tried to put a bullet before the next line and it was actually yelling at me for not having indented the line after yet, but i thought it was yelling at me for the bullet itself because that's where it put the red gunk
sarahzrf (Jan 16 2024 at 20:16):
not used to whitespace sensitivity in my proof assistant
sarahzrf (Jan 16 2024 at 20:17):
okay that makes more sense lol
sarahzrf (Jan 16 2024 at 20:19):
btw, glimpse of lean formats some of its proofs like
example foo : a = c := by {
calc
a = b := _
_ = c := _
}
which seems excessive to me when
example foo : a = c := calc
a = b := _
_ = c := _
works. is the former actually considered idiomatic over the latter?
sarahzrf (Jan 16 2024 at 20:20):
or is it just trying to avoid confusing readers as to whether you always need a by {}
Yaël Dillies (Jan 16 2024 at 20:21):
I believe the point is that with the {}
around you get unsolved goals errors on the }
, not on the by
(which beginners find very confusing)
Kevin Buzzard (Jan 16 2024 at 20:22):
I suspect that the (edit: I just tried this and as Yael says below this is not true)by
really does change things. The proofs you fill in on the various lines will be expecting terms without the by
and tactics with the by
.
Kyle Miller (Jan 16 2024 at 20:22):
Yaël's said the reason for by { ... }
. It puts the error in a place that someone first learning Lean might notice it.
Yaël Dillies (Jan 16 2024 at 20:22):
In general, yes, but here term-mode calc
and tactic mode calc
should leave you the same kinds of holes.
Kyle Miller (Jan 16 2024 at 20:23):
But also, you need the by
to go into tactic mode. Pedagogically it's easier to stay in the realm of tactics than to discuss terms vs tactics. Plus, in your example, the := _
's cause new goals in the tactic version. That's not allowed in the term version.
Kevin Buzzard (Jan 16 2024 at 20:23):
Another fix for the "error in a weird place" which I'm experimenting with in my course this year is to encourage students to end all proofs with done
sarahzrf (Jan 16 2024 at 20:24):
my question though is basically just, in actual lean code do people stylistically tend to bother with the redundant do {}
around proofs that are just a single calc
sarahzrf (Jan 16 2024 at 20:24):
huh, what do you mean about causing new goals
Kyle Miller (Jan 16 2024 at 20:26):
You see that there's an error in your foo
example without the by
right?
Though to get new goals with by
you have to use ?_
instead of _
, otherwise it gives a similar error.
example (a b c : Nat) : a = c := by
calc
a = b := ?_
_ = c := ?_
-- Two goals:
sorry
sorry
sarahzrf (Jan 16 2024 at 20:27):
is it like, in the term version lean needs to be able to individually automatically—yeah alright
sarahzrf (Jan 16 2024 at 20:27):
i was actually also wondering what the distinction between _ and ?_ is
sarahzrf (Jan 16 2024 at 20:27):
does _ ask for the elaborator to fill a hole and ?_ spawns a new goal?
Kyle Miller (Jan 16 2024 at 20:27):
The calc ...
tactic is short for refine calc ...
, and in refine
, each ?a
or ?_
turns into a new goal.
Kyle Miller (Jan 16 2024 at 20:28):
Yes, _
placeholders need to be solvable by unification.
sarahzrf (Jan 16 2024 at 20:28):
so you can't use ?_ outside of a tactic script then
sarahzrf (Jan 16 2024 at 20:28):
actually wait
sarahzrf (Jan 16 2024 at 20:28):
right, they aren't even the same type are they
sarahzrf (Jan 16 2024 at 20:28):
actually hold on
Kevin Buzzard (Jan 16 2024 at 20:29):
Right, ?_
is an interactive thing. If you're in term mode then you'd better be writing the term in full.
sarahzrf (Jan 16 2024 at 20:29):
so—you can use either _ or ?_ as a tactic and you can use either _ or ?_ as a term, but you can only use ?_ as a term if the superterm it's part of is in a refine
, i'm guessing?
sarahzrf (Jan 16 2024 at 20:30):
what's the difference between _ and ?_ as tactics, though?
Kevin Buzzard (Jan 16 2024 at 20:30):
refine
is a tactic but it will consume ?_
and give you a new goal (still in tactic mode)
sarahzrf (Jan 16 2024 at 20:30):
oh wait no i'm confused again
sarahzrf (Jan 16 2024 at 20:30):
one moment, let me look at this code again lol
Patrick Massot (Jan 16 2024 at 20:31):
sarahzrf said:
my question though is basically just, in actual lean code do people stylistically tend to bother with the redundant
do {}
around proofs that are just a singlecalc
In actual lean code there is no {}
at all. This is purely a beginner thing.
Kyle Miller (Jan 16 2024 at 20:32):
At risk of confusing you, you can do some really weird things with these ?x
metavariables outside of tactics (nobody does this; it's not good practice). If you stick with the un-named version ?_
then I'm not sure there's anything you can do with them outside of tactics.
import Mathlib.Tactic
theorem foo : ?x = (by haveI : ?x := 1; exact ?x) := rfl
#print foo
/--
theorem foo : ℕ = ℕ :=
rfl
-/
sarahzrf (Jan 16 2024 at 20:33):
this makes perfect sense kyle
sarahzrf (Jan 16 2024 at 20:34):
well i'm maybe a tiny bit surprised that actually typechecks lol
sarahzrf (Jan 16 2024 at 20:35):
so okay hold on
sarahzrf (Jan 16 2024 at 20:35):
something i was going to ask about was a kind of like. scoping thing—
sarahzrf (Jan 16 2024 at 20:36):
like, if you're in the middle of a proof script and then you write a term in the middle there that contains a by
and then somewhere in that by
you write a term that contains a ?_
, which tactic script gets the goal
sarahzrf (Jan 16 2024 at 20:36):
But i was asking this under the impression that metavariables sort of did not exist in the term language ordinarily unless you were in a proof context. But tbh i probably shouldve expected that they did, coq works that way too
sarahzrf (Jan 16 2024 at 20:37):
Um. Hm
sarahzrf (Jan 16 2024 at 20:37):
My question still kinda stands though, now that I think about it
sarahzrf (Jan 16 2024 at 20:37):
Do we have a kind of situation where metavariables and goals are sort of the same thing or what
Kevin Buzzard (Jan 16 2024 at 20:38):
After a by
you are in tactic mode so you don't write a term, you write a tactic.
sarahzrf (Jan 16 2024 at 20:38):
yes, i know, tactics often have terms as arguments
sarahzrf (Jan 16 2024 at 20:38):
i elided a step
Kevin Buzzard (Jan 16 2024 at 20:39):
Right, like refine
. So if you are in tactic mode and write refine \<?_, ?_\>
and this makes sense then you're still in tactic mode but now you have two goals, and most tactics will just apply to the first goal, but the universe has split into two at this point.
Kevin Buzzard (Jan 16 2024 at 20:41):
and if you were lucky enough to have a metavariable around when the universe split into two then you can do some wacky things like assigning it in one universe and having it magically be assigned in the other universe.
sarahzrf (Jan 16 2024 at 20:41):
i understand that
sarahzrf (Jan 16 2024 at 20:41):
let me write down an example of what i meant
Kyle Miller (Jan 16 2024 at 20:42):
sarahzrf said:
Do we have a kind of situation where metavariables and goals are sort of the same thing or what
They are exactly the same thing. Metavariables that are meant to be goals are also marked as being "synthetic opaque" ("synthetic" as in something will solve for them, namely the user). Generally, unification avoids solving for these and will even throw an error if anything tries to (hence "opaque" I guess). Goal metavariables are also recorded in a list of goals in the tactic state. It's up to tactics to remember to add lingering goal metavariables to this list of goals.
sarahzrf (Jan 16 2024 at 20:43):
blah blah
blah
refine \<3, by {
refine 2 + ?_
/- you are here -/
}\>
sarahzrf (Jan 16 2024 at 20:44):
presumably at the marked point we get to refine the ?_
hole
sarahzrf (Jan 16 2024 at 20:44):
But say we put no more tactics there and instead skipped to the end of what i've written so far
sarahzrf (Jan 16 2024 at 20:44):
If we focused there, would we also from there get to refine the ?_
hole?
sarahzrf (Jan 16 2024 at 20:44):
Or is there some kind of scoping going on?
Kyle Miller (Jan 16 2024 at 20:44):
The list of goals is "scoped" to the current tactic block, and a tactic block requires that all lingering goals in its goal list be solved for.
sarahzrf (Jan 16 2024 at 20:45):
perfect, thank you
Kyle Miller (Jan 16 2024 at 20:45):
Potentially you could circumvent this and get refine
to capture lingering goals, but it would take a hack, or perhaps a new tactic that's just for doing this.
Kyle Miller (Jan 16 2024 at 20:48):
Yeah, this can be done:
import Mathlib.Tactic
open Lean Elab Tactic in
elab "defer_all" : tactic => do
setGoals []
example : ∃ x : Nat, x = x := by
refine ⟨(by refine 1 + ?_; defer_all), ?_⟩
/-
case refine_1
⊢ 1 + ?refine_2 = 1 + ?refine_2
case refine_2
⊢ ℕ
-/
Kyle Miller (Jan 16 2024 at 20:49):
(refine
works by walking through the expression it's given, collecting all ?_
metavariables, and adding them to the list of goals)
sarahzrf (Jan 16 2024 at 20:50):
yea, coq has a refine
tactic too
Kyle Miller (Jan 16 2024 at 20:51):
sarahzrf said:
But i was asking this under the impression that metavariables sort of did not exist in the term language ordinarily unless you were in a proof context. But tbh i probably shouldve expected that they did, coq works that way too
You are right that completed terms do not have metavariables, but metavariables are essential to both elaboration and tactic execution, and they're part of docs#Lean.Expr -- it's just that the kernel throws an exception if it ever encounters an Expr.mvar
.
sarahzrf (Jan 16 2024 at 20:51):
Although coq's refine
doesnt have a way of distinguishing between goal holes and should-be-solved-by-the-elaborator holes, which can be awkward
sarahzrf (Jan 16 2024 at 20:52):
Kyle Miller said:
sarahzrf said:
But i was asking this under the impression that metavariables sort of did not exist in the term language ordinarily unless you were in a proof context. But tbh i probably shouldve expected that they did, coq works that way too
You are right that completed terms do not have metavariables, but metavariables are essential to both elaboration and tactic execution, and they're part of docs#Lean.Expr -- it's just that the kernel throws an exception if it ever encounters an
Expr.mvar
.
:thought: what does this mean semantically...
Kyle Miller (Jan 16 2024 at 20:53):
sarahzrf said:
Although coq's
refine
doesnt have a way of distinguishing between goal holes and should-be-solved-by-the-elaborator holes, which can be awkward
Yeah, it could be awkward in Lean 3 also, which didn't have this distinction either.
sarahzrf (Jan 16 2024 at 20:53):
entirely too many times ive tried to refine
in coq and ended up with like 5 random typeclass instances as goals :sob:
Kyle Miller (Jan 16 2024 at 20:54):
Lean 4 has refine'
to relive the Lean 3 days. This can be useful sometimes.
Kyle Miller (Jan 16 2024 at 20:55):
Though the way typeclass instances are synthesized, I think you never end up with unsolved instance goals with refine
/refine'
.
sarahzrf (Jan 16 2024 at 20:55):
coq's typeclass machinery is extremely fucking funny
sarahzrf (Jan 16 2024 at 20:56):
You can put arbitrary tactic scripts into it
Kyle Miller (Jan 16 2024 at 20:57):
sarahzrf said:
:thought: what does this mean semantically...
I'm not sure what the question is exactly, but I'll say a few things. We've got the elaborator and the kernel, and the kernel uses the same Lean.Expr
as the elaborator, but it's effectively using the subtype of Lean.Expr
that does not contain the Lean.Expr.mvar
constructor, which is used for metavariables. The elaborator needs metavariables to handle implicit arguments, typeclass instance arguments, tactic blocks, etc. etc.
sarahzrf (Jan 16 2024 at 20:58):
yeah i followed that, i wasnt asking a specific question, the pl part of my brain just caught on what you said and reflexively started Wondering Things
sarahzrf (Jan 16 2024 at 20:58):
thought bubble emoji indicated idle curiosity
sarahzrf (Jan 16 2024 at 21:00):
very much a tangent
sarahzrf (Jan 16 2024 at 21:00):
anyway i should probably get back to learning the basics. lol
Kyle Miller (Jan 16 2024 at 21:03):
So let's not get started on how refine fun x => ?_
manages to create a goal state with an extra x
variable in its local context, at the level of terms :-)
sarahzrf (Jan 16 2024 at 21:05):
what exactly is problematic there?
sarahzrf (Jan 16 2024 at 21:08):
huhhh, you can rewrite by iffs... is this accomplished thru setoidy mechanisms or is it just propext?
Kyle Miller (Jan 16 2024 at 21:08):
propext
Kyle Miller (Jan 16 2024 at 21:09):
You can use by?
to see the term a tactic produced by the way.
sarahzrf (Jan 16 2024 at 21:09):
:rolling_eyes: typical cheaters
Kyle Miller (Jan 16 2024 at 21:09):
or use the show_term
tactic, which has the syntax show_term *tactic*
Kyle Miller (Jan 16 2024 at 21:10):
It's not cheating if we want Prop
to be equivalent to Bool
, right?
sarahzrf (Jan 16 2024 at 21:10):
u dont even have computational behavior for ur system. ur cheating. ur just positing new terms willy nilly & violating the harmony of introduction and elimination forms
sarahzrf (Jan 16 2024 at 21:10):
it makes me sick
sarahzrf (Jan 16 2024 at 21:11):
on the other hand. wow is it convenient. hmmm
sarahzrf (Jan 16 2024 at 21:14):
hmm, this example in Glimpse of Lean is using have
and then immediately rw
ing by the thing we had. is there no tactic for doing this? in coq for example you can say replace foo with bar by tactic
where tactic
proves foo = bar
Yaël Dillies (Jan 16 2024 at 21:16):
obtain rfl : foo = bar := by tactic
will do (assuming foo
is a variable)
sarahzrf (Jan 16 2024 at 21:17):
well, the two sides arent identifiers, foo
and bar
were metavariables and not variables there :P
sarahzrf (Jan 16 2024 at 21:17):
i wouldve written x
and y
if i had variables in mind
Kyle Miller (Jan 16 2024 at 21:21):
example (a b c d : Nat) : a + b + c = d := by
conv in a + b => equals 1 => sorry
-- 1 + c = d
sorry
sarahzrf (Jan 16 2024 at 21:22):
i have no idea what =>
, conv
, or equals
are doing here sorry lol
Kyle Miller (Jan 16 2024 at 21:23):
It's doing replace a + b with 1 by admit
sarahzrf (Jan 16 2024 at 21:23):
well i can see that, i just mean i dont understand enough lean for this to teach me something
sarahzrf (Jan 16 2024 at 21:24):
Like, i dont understand the pieces yet so this is not showing me a way to put them together
Kyle Miller (Jan 16 2024 at 21:25):
I imagine you've learned that Lean has an analogue? You don't need to understand the pieces to be able to use it.
Kyle Miller (Jan 16 2024 at 21:25):
If I gave you a single tactic to do it, you probably wouldn't be complaining that you don't know how it's implemented :wink:
sarahzrf (Jan 16 2024 at 21:25):
well, i dont like using things without understanding how they work
sarahzrf (Jan 16 2024 at 21:25):
eh, true
sarahzrf (Jan 16 2024 at 21:53):
wait, you can use calc
with a chain of multiple relations?
sarahzrf (Jan 16 2024 at 21:53):
that's cool
sarahzrf (Jan 16 2024 at 21:53):
what is the typeclsas underlying it exactly?
Patrick Massot (Jan 16 2024 at 23:17):
@sarahzrf you are very welcome here, but you should know that you are not at all in the intended audience of the Glimpse of Lean tutorial. It may be very frustrating for you to keep going in this direction. You will probably have more fun with #tpil.
sarahzrf (Jan 16 2024 at 23:22):
Patrick Massot said:
sarahzrf you are very welcome here, but you should know that you are not at all in the intended audience of the Glimpse of Lean tutorial. It may be very frustrating for you to keep going in this direction. You will probably have more fun with #tpil.
i saw tpil first and quite frankly it looks more frustrating to me, i dont need concepts like "terms have types" explained to me lol
sarahzrf (Jan 16 2024 at 23:23):
i decided glimpse of lean looks nice because at least it's actually all code so i can skip directly to learning what the syntax is like
Patrick Massot (Jan 16 2024 at 23:40):
I see your point, but I'm still worried Glimpse of Lean won't answer a lot of your questions. It is really meant for people who are not interested in type theory.
sarahzrf (Jan 16 2024 at 23:42):
i mean, i dont need type theory explained for me, i only need lean explained to me
Kyle Miller (Jan 17 2024 at 00:02):
I think Patrick would also include more generally "people who are immediately interested in low-level aspects of Lean".
sarahzrf said:
i saw tpil first and quite frankly it looks more frustrating to me, i dont need concepts like "terms have types" explained to me lol
I don't really understand the issue, or what's funny about a book not being aware of what you personally already know -- here's a friendly reminder that you can skip content that you're familiar with :smile: (Of course, carry on with Glimpse of Lean if you're happy enough with it.)
sarahzrf (Jan 17 2024 at 00:05):
well, i was using that as one example of a more general issue, which is that tpil spends a lot of time actually explaining the concepts underlying lean. which is a good thing! but in my case it's irrelevant to me and means i have to skim heavily, because i already know the vast majority of those concepts. i'd really only be reading it for the code samples
sarahzrf (Jan 17 2024 at 00:09):
the "lol" wasnt meant to indicate that i found something funny per se, its almost more like a tone particle in function, idk. i can speak less casually if you like
Kyle Miller (Jan 17 2024 at 01:12):
I wouldn't want this place to be devoid of character, and there's room for a casual tone, but it's worth being aware that it tends to be more professional here than maybe other forums. Generally communication tends to be more functional than conversational, but that's just a tendency, not a rule. I don't want to put any damper on your excitement learning Lean or feeling like you can hang out here to discuss or ask questions about Lean.
For me, I started back in the Lean 3 days, going through Kevin Buzzards NNG and then a Patrick Massot's tutorial, and from there I relied on my past experience with functional programming (including some Agda), consulted the Lean 3 reference manual, and hung out here picking up things from what people were talking about. Oh, I had also opened up the HoTT book a few times, if that counts for anything. I think it's fair using whatever materials speak to you; I myself have only read #tpil randomly, skimming chapters here and there. My first question on the Zulip was about a frustrating non-beta-reduced lambda that was hidden because of the pretty printer, which I could deduce because I knew lambda calculus, and because I was following a math-oriented tutorial I didn't have the tools to deal with it. (An answer is dsimp only
by the way.)
sarahzrf (Jan 24 2024 at 22:07):
Does Lean have some kind of command that searches the types of all loaded definitions for a given subterm? For example, is there some way of saying something like
#search _ + (_ + _) = (_ + _) + _
to look for associativity theorems about +
?
Damiano Testa (Jan 24 2024 at 22:10):
@loogle _ + (_ + _) = (_ + _) + _
Let's see this!
sarahzrf (Jan 24 2024 at 22:10):
Is there something that works from inside a Lean session?
loogle (Jan 24 2024 at 22:10):
Failure! Bot is unavailable
Damiano Testa (Jan 24 2024 at 22:11):
Maybe #find
?
sarahzrf (Jan 24 2024 at 22:12):
How do I use #find
?
Damiano Testa (Jan 24 2024 at 22:12):
(I never used it, though.)
Kevin Buzzard (Jan 24 2024 at 23:29):
If you've imported some of mathlib it should just work?
import Mathlib.Data.Real.Sqrt -- or whatever
#find (?a -> ?b) -> List ?a -> List ?b -- finds List.map and some other stuff
See examples at https://loogle.lean-lang.org/
sarahzrf (Jan 24 2024 at 23:30):
Cool
sarahzrf (Jan 24 2024 at 23:31):
Is there a way to do an AND?
sarahzrf (Jan 24 2024 at 23:31):
for example, if i want to search for a theorem that includes both Continuous ?f
and Monotone ?f
in its statement
sarahzrf (Jan 24 2024 at 23:50):
Also: I see that Lean has sections and section variables. Does it have full-on ML-style modules?
David Renshaw (Jan 25 2024 at 00:42):
My understanding is
- in Lean terminology, a "module" = "file" = "compilation unit"
- Lean also has namespaces, which are orthogonal to modules
- Lean does not have ML-style modules/functors, but can support a lot of the same patterns via dependent types
sarahzrf (Jan 25 2024 at 02:40):
how do i declare a class instance variable
sarahzrf (Jan 25 2024 at 02:41):
i wrote variable (C : Type) [Category C]
and it's complaining
invalid binder annotation, type is not a class instance
?m.1425
use the command `set_option checkBinderAnnotations false` to disable the check
Kevin Buzzard (Jan 25 2024 at 07:21):
If you mean mathematical categories then maybe you want open CategoryTheory
somewhere
Kevin Buzzard (Jan 25 2024 at 07:21):
Kevin Buzzard (Jan 25 2024 at 07:22):
Difficult to tell without a #mwe
sarahzrf (Jan 25 2024 at 07:22):
Ah yes, the issue was that it was Category
and not CategoryTheory.Category
sarahzrf (Jan 25 2024 at 07:23):
Why isn't the error that Category
doesn't exist, then?
Mauricio Collares (Jan 25 2024 at 07:27):
Do you get a better error with set_option autoImplicit false
? If so, see https://lean-lang.org/lean4/doc/autobound.html
sarahzrf (Jan 25 2024 at 07:31):
#set_option autoImplicit false
gives an error, but oddly enough it does result in a better error message anyway
sarahzrf (Jan 25 2024 at 07:32):
Hm, Category
isn't a lowercase letter or Greek, so why is that link relevant?
Mauricio Collares (Jan 25 2024 at 07:38):
It really is set_option
without the #
. You can disable auto implicits for non-single-character identifiers with set_option relaxedAutoImplicit false
, I think. The single-letter restriction was relaxed after the manual was written, I think (lean4#1011).
Mauricio Collares (Jan 25 2024 at 07:40):
LSP should highlight autoimplicits differently but it can be a bit subtle. There are some threads here in Zulip containing tweaks to the color scheme.
Kevin Buzzard (Jan 25 2024 at 09:36):
There's this great footgun switched on in lean by default which goes "if the user makes a typo, just create a new type called that and press on".
Kevin Buzzard (Jan 25 2024 at 09:36):
Once you're aware of it it's great. When you're not, it's as confusing as hell
Last updated: May 02 2025 at 03:31 UTC