elan install stable
. Para iniciar un proyecto nuevo, sigan las instrucciones del manual oficial de Lean.Lean viene con una biblioteca básica incluída. El módulo Init.Prelude
es importado automáticamente cuando se crea un archivo Lean nuevo.
Hay otras bibliotecas, que pueden ser utilizadas como dependencies en un proyecto Lean dado:
Tanto Lean como sus bibliotecas son de código abierto (bajo una licencia Apache 2.0).
El código está de libre acceso en GitHub.
Kevin Buzzard está liderando actualmente la formalización del Último Teorema de Fermat (2024-2029). El plan de la prueba se puede visualizar de la siguiente manera gracias a Lean blueprint:
El código de colores muestra el avance del proyecto hacia su finalización.
Las siguientes herramientas son indispensables para escribir código en Lean:
(?a -> ?b) -> List ?a -> List ?b
.order subgroup divides order group
o dim V = dim (Ker u) + dim (Im u)
.Los siguientes libros en línea son las referencias estándar de la comunidad Leanprover:
lake init
o lake new
(prueben lake --help
primero). Esto también se puede hacer directamente desde VS Code, usando la extensión de Lean 4.Dependiendo de a quién le pregunten, un tipo puede ser visto como:
(3 : Nat)
, (-4 : ℤ)
, ([1, 2, 3] : List Nat)
, (Nat.mul : Nat → Nat → Nat)
.Cada término tiene un tipo asignado, que es parte de su definición como término: dado que no tienen el mismo tipo, (3 : Nat)
y (3 : ℤ)
son objetos diferentes. Expresiones como x := x + 1
no están bien tipadas y no tienen sentido en un lenguaje de programación funcional.
En Lean, se puede averiguar el tipo de un término usando el comando #check
:
#check 42 -- 42 : Nat
#check Nat -- Nat : Type
#check Nat.mul -- Nat.mul : Nat → Nat → Nat
#check "42" -- "42" : String
#check 1 + 1 -- 1 + 1 : Nat
#check 1 + 1 = 2 -- 1 + 1 = 2 : Prop
#check 1 + 1 > 2 -- 1 + 1 > 2 : Prop
Nótese que una expresión bien tipada puede ser reconocida como una proposición independientemente de si es "matemáticamente correcta". La expresión 2 + 2 = 5, por ejemplo, es sintácticamente correcta (una igualdad entre dos números naturales). En contraste, una expresión común como 2 * (3 + 1) = 2 * 3 + 2 * 1 = 8
no está bien tipada.
Es de sentido común no mezclar cantidades que no están relacionadas entre sí. Aquí va un ejemplo de una suma mal tipada.
Image credits: MikeGogulski, CC BY-SA 3.0.
La arquitectura de un asistente de prueba interactivo se puede representar de la siguiente manera.
Créditos de la imagen: Assia Mahboubi.
f : X → Y
son los objetos básicos de un lenguaje como Lean.def fact : Nat → Nat
| 0 => 1
| k + 1 => (k + 1) * fact k
#check fact -- fact : Nat → Nat
#check fact 5 -- fact 5 : Nat
#eval fact 5 -- 120
f : A → B → C
, entonces en la expresión f a b
, el término f a
es una función de B
a C
, y se aplica a b
.def sum : Nat → Nat → Nat := fun x y ↦ x + y
#check sum 3 -- sum 3 : Nat → Nat
#eval sum 3 5 -- 8
Si en lugar de eso definimos def sum₁ : Nat → Nat → Nat := fun x ↦ (fun y ↦ x + y)
, entonces obtenemos sum = sum₁
, por reflexividad.
f : A → B → C → D → E
, entonces para todos a : A
, b : B
, c : C
, d : D
, tenemos f a b c d : E
.f : A → (B → C) → D → E
, que toma como argumentos un término a : A
, una función u : B → C
y un término d : D
, devolviendo un término de tipo E
.def f : Nat → (Nat → ℝ) → ℝ → ℝ :=
fun (n : Nat) (u : Nat → ℝ) (x : ℝ) ↦ 2 ^ n * u n + x
def v : Nat → ℝ := fun n ↦ 2 * n
#eval f 3 v (-6) -- 42
El tipo inductivo más famoso en matemáticas es probablemente el tipo Nat
, cuya definición se remonta a Giuseppe Peano en 1889.
inductive Nat : Type
| zero : Nat
| succ : Nat → Nat
Las definiciones inductivas producen funciones especiales llamadas constructores. En este caso, hay dos de ellos (dos reglas de introducción para términos de tipo Nat
):
Nat.zero : Nat
(una función cuyo valor es su propio nombre se llama un átomo, pueden verla como una función del tipo Unit
al tipo Nat
, si prefieren).Nat.succ : Nat → Nat
(la función sucesor), que dice que para cada n : Nat
hay un término n.succ : Nat
(dot notation para Nat.succ (n : Nat)
).La definición del producto de dos tipos como un tipo inductivo es menos usual en matemáticas.
inductive Prod (X Y : Type) : Type
| mk : X → Y → Prod X Y
Esto significa que los términos del tipo Prod X Y
se introducen a través del constructor Prod.mk : X → Y → Prod X Y
. En otras palabras, para todo x : X
y todo y : Y
, el término Prod.mk x y
es de tipo Prod X Y
y esta es la única regla de introducción que hay para términos de tipo X × Y
. En Lean, el tipo Prod X Y
se denota por X × Y
y sus términos por ⟨x, y⟩
(corchetes angulares).
f : Nat → Nat
, como la función factorial. Fue definida por inducción. Dado que el constructor Nat.succ
es una función de Nat
a Nat
, el principio de inducción para Nat
incluye una llamada recursiva: para definir f (n + 1)
, podemos usar n
y f n
, como en la definición de fact (n + 1)
.Nat
: cada tipo inductivo tiene un principio de inducción asociado. Para el producto, implica en particular que, para definir una función f : X × Y → Z
, basta con definirla en los términos canónicos Prod.mk x y
. En la práctica, esto se hace a través de pattern matching (búsqueda de patrones).def pr₁ {X Y : Type} : X × Y → X
| Prod.mk x y => x
inductive Sum (X Y : Type) : Type
| inl : X → Sum X Y
| inr : Y → Sum X Y
def charac_second_summand {X Y : Type} : X ⊕ Y → Bool
| Sum.inl x => (false : Bool)
| Sum.inr y => (true : Bool)
Sintaxis de Lean Natural Number Game
Dato curioso: visto a menudo en ejemplos de Lean,
De hecho, el tipo de booleanos también es un tipo inductivo, con dos constructores.