Zulip Chat Archive
Stream: lean4
Topic: Confused by the order of the implicit argument insertion
Tim Hunter (Dec 16 2021 at 18:48):
Hello,
I am a bit confused by the (very useful) feature p.foo a b c where p is a structure. According to the documentation:
https://leanprover.github.io/lean4/doc/struct.html
this is translated as MyStructure.foo a b c p. However, it seems that the compiler is currently more lenient in the order of arguments
namespace List
def f2: List α -> Nat -> Nat
| _, x => x
def f3: Nat -> List α -> Nat
| x, _ => x
def g: List α -> List α -> Nat
| _, l => l.length
end List
let l : List Int := [1,2,3]
assert! l.f2 1 = 1
assert! l.f3 1 = 1
-- Can you guess the outcome?
assert! [].g [1] = 1
As a beginner, I try to be careful as a result because the outcome is not always clear to me. Am I missing something?
Horatiu Cheval (Dec 16 2021 at 19:15):
It’s not about implicitness, but about dot notation. When using dot notation, the argument before the dot is passed to the first argument of the function that matches the namespace (List in your case). So [].g [1]
means g [] [1]
, whose result is clearly 1
Tim Hunter (Dec 16 2021 at 19:53):
So then, why would the f3
example work? Shouldn't it be translated to List.g l 1
, which will then fail? It currently compiles and executes without issue.
Horatiu Cheval (Dec 16 2021 at 19:57):
l.f3 1
is translated to List.f3 1 l
because 1
is not a List
. l
is sent to the first argument that matches the type List
which in this case is the second one
Tim Hunter (Dec 16 2021 at 19:58):
Ah indeed, reading more carefully the documentation, I now understand: "given an expression p.foo x y z, Lean will insert p at the first argument to foo of type Point". Unlike a language like python for example, it will look at type of the argument during the desugaring.
Since this is the case, are there some best practices? For example, most OO languages would use the first argument but Haskell tends to consider the last argument.
Horatiu Cheval (Dec 16 2021 at 20:04):
With python do you mean the self
argument which normally (or maybe even necessarly, I haven't tried otherwise) is the first argument of a method?
Horatiu Cheval (Dec 16 2021 at 20:09):
I think in Haskell an important design decision regarding the order of the arguments is to decide what is the most likely situation in which you will want to partially apply your function, and a good order of the arguments will make that considerably easier. I think this still holds true for Lean, because function application follows the same idea. But even if you order the arguments so that that kind of writing is easier for you, you are then still able to use dot notation.
Horatiu Cheval (Dec 16 2021 at 20:12):
For instance map
from the standard library has type List.map (f : α → β) : List α → List β
. This allows you to easily write map f
for some f
in order to succintly state that you want to applyf
to lists, but you may still do l.map f
if it's more readable in the context. But I don't know whether there are official style guidelines for this
Horatiu Cheval (Dec 16 2021 at 20:14):
Personally, I think one of the nicest things about dot notation is that it allows you to call functions from namespaces with long names without explicitly writing them or opening them. I.e. if you already have some x : Namespace1.Namespace2.Namespace3
and some function f
from the same namespace, you may simply write x.f
without worrying about the namespace
Last updated: Dec 20 2023 at 11:08 UTC