Zulip Chat Archive

Stream: lean4

Topic: Unexpected overloading with export command


view this post on Zulip François G. Dorais (Feb 09 2021 at 02:28):

I was a bit surprised that the following shows two definitions for rfl instead of some kind of error message.

class Reflexivity {α} (r : α  α  Prop) : Prop where refl : (x : α)  r x x

abbrev Reflexivity.rfl {α r x} := @Reflexivity.refl α r x

export Reflexivity (refl rfl)

#print rfl

But #check rfl does give an error:

Dev/Relations.lean:11:7: error: ambiguous, possible interpretations
rfl
rfl

I would expect an error at the export but maybe there is something deeper going on.

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:31):

That works also in lean 3

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:32):

When you have open namespaces you can get into a situation where a name is overloaded; this will cause an error if you try to use it

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:33):

def A.foo := 1
def B.foo := 2
open A B
#check foo
-- ambiguous overload, possible interpretations
--   B.foo
--   A.foo

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:33):

an export is just a global open

view this post on Zulip François G. Dorais (Feb 09 2021 at 02:33):

Oh, I see. So export works as a global open.

view this post on Zulip François G. Dorais (Feb 09 2021 at 02:34):

(As opposed to a new declaration.)

view this post on Zulip François G. Dorais (Feb 09 2021 at 02:38):

That's not what I expected. I think I'll avoid exports from now on. Nobody should have that much power!

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:38):

Yes, I don't think it's used in mathlib at all, and the few uses in core are for things like option.some

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:39):

usually we just put things in the root namespace if we want them to be used without a qualifier in all contexts

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:39):

I guess you can't do that for constructors of a data type like option though

view this post on Zulip François G. Dorais (Feb 09 2021 at 02:42):

Wouldn't an abbreviation work just as well?

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:43):

As you observed, an export is not the same as an abbreviation, the latter creates a new definition, meaning that tactics and so on see a different term and can do different things

view this post on Zulip François G. Dorais (Feb 09 2021 at 02:49):

I think I would prefer a new definition, but that's just my personal opinion. I'm happy writing a bunch of abbreviations instead of exports. And I could probably write a macro to automate this if necessary... (Lean 4 macros rock!)

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:51):

I just feel bad for the kernel sometimes, seeing and typechecking all these useless definitions that are equal to other named things

view this post on Zulip Mario Carneiro (Feb 09 2021 at 02:52):

I prefer parser-only abbreviations, which you can mostly get via notation and macros

view this post on Zulip François G. Dorais (Feb 09 2021 at 02:53):

Good point but the kernel doesn't feel anything... though _you_ could feel your cpu overheating. :smiley: Thanks for the help Mario!

view this post on Zulip Kyle Miller (Feb 09 2021 at 04:13):

I think what open and export do specifically is something like the following. At any given moment you have a list of known symbols along with a current namespace.

  • open foo takes all the names in the foo namespace and adds them to the list of known symbols. This way you can reference those symbols without qualifying them with foo
  • export foo (symbols...) does open foo (symbols...) and also adds all those symbols to the current namespace. The effect is that whoever then later opens or exports this namespace will get those symbols. (And if it's at the top level, everyone gets them!)

For example, the export below essentially creates a symbol foo.x. You still have to open foo if you're not in the foo namespace to have an x that stands for foo.bar.x.

namespace foo

structure bar where
    x : Nat
export bar (x)

end foo

It can be useful when you want to curate a namespace.

view this post on Zulip Sebastian Ullrich (Feb 09 2021 at 08:44):

open foo takes all the names in the foo namespace and adds them to the list of known symbols. This way you can reference those symbols without qualifying them with foo

Not quite; this is how Lean 3 worked, but in Lean 4, open makes symbols available that haven been declared in the namespace even after the open command.

view this post on Zulip Kyle Miller (Feb 10 2021 at 17:50):

What I said ends up being incorrect for Lean 3 as well -- I thought I had tested it before, but it seems that export only makes symbols available when you later re-enter or open the namespace. That's to say, in the Lean 3 version of that code the export does not imply the existence of a foo.x.

(Something I've been wondering is where the idea for Lean's namespaces might have come from. They are very similar to Common Lisp's symbol packages, simplified for the better, but I could imagine they might also have come from an Algol/Pascal-syntax version of Agda modules, especially with there being parameter variables.)


Last updated: May 07 2021 at 13:21 UTC