* Lean declarations ** Definitions The command =definition= declares a new constant/function. The identity function is defined as #+BEGIN_SRC lean definition id {A : Type} (a : A) : A := a #+END_SRC We say definitions are "transparent", because the type checker can unfold them. The following declaration only type checks because =+= is a transparent definition. Otherwise, the type checker would reject the expression =v = w= since it would not be able to establish that =2+3= and =5= are "identical". In type theory, we say they are _definitionally equal_. #+BEGIN_SRC lean import data.fixed_list data.nat open nat check λ (v : fixed_list nat (2+3)) (w : fixed_list nat 5), v = w #+END_SRC Similarly, the following definition only type checks because =id= is transparent, and the type checker can establish that =nat= and =id nat= are definitionally equal, that is, they are the "same". #+BEGIN_SRC lean import data.nat definition id {A : Type} (a : A) : A := a check λ (x : nat) (y : id nat), x = y #+END_SRC ** Theorems In Lean, a theorem is just an =opaque= definition. We usually use =theorem= for declaring propositions. The idea is that users don't really care about the actual proof, only about its existence. As described in previous sections, =Prop= (the type of all propositions) is _proof irrelevant_. If we had defined =id= using a theorem the previous example would produce a typing error because the type checker would be unable to unfold =id= and establish that =nat= and =id nat= are definitionally equal. ** Private definitions and theorems Sometimes it is useful to hide auxiliary definitions and theorems from the module interface. The keyword =private= allows us to declare local hidden definitions and theorems. A private definition is always opaque. The name of a =private= definition is only visible in the module/file where it was declared. #+BEGIN_SRC lean import data.nat open nat private definition inc (x : nat) := x + 1 private theorem inc_eq_succ (x : nat) : succ x = inc x := rfl -- The definition inc and theorem inc_eq_succ are not visible/accessible -- in modules that import this one. #+END_SRC ** Protected definitions and theorems Declarations can be be organized into namespaces. In the previous examples, we have been using the namespace =nat=. It contains definitions such as =nat.succ= and =nat.add=. The command =open= creates the aliases =succ= and =add= to these definitions. An alias will not be created for a _protected definition_ unless the user explicitly request it. #+BEGIN_SRC lean import data.nat open nat namespace foo definition two : nat := 2 protected definition three : nat := 3 end foo open foo check two -- The following command produces a 'unknown identifier' error /- check three -/ -- We have to use its fully qualified name to access three check foo.three -- If the user explicitly request three, then an alias is created open foo (three) check three #+END_SRC