Built with Alectryon, running Lean4 v4.8.0. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use instead of Ctrl.
Hover-Settings: Show types: Show goals:

LAMR

Experimenting with code from https://github.com/avigad/lamr

3. Lean as a Programming Language

3.1. About lean

https://avigad.github.io/lamr/using_lean_as_a_programming_language.html

2 + 2 : Nat
2: Nat
2
+
2: Nat
2
-5 : Int
-
5: Int
5
[1, 2, 3] : List Nat
[
1: Nat
1
,
2: Nat
2
,
3: Nat
3
]
#[1, 2, 3] : Array Nat
#[
1: Nat
1
,
2: Nat
2
,
3: Nat
3
]
Array.{u} : Type u) : Type u
Array: Type u → Type u
Array
(1, 2, 3) : Nat × Nat × Nat
(
1: Nat
1
,
2: Nat
2
,
3: Nat
3
)
"hello world" : String
"hello world": String
"hello world"
Bool.true : Bool
true: Bool
true
fun x => x + 1 : Nat Nat
fun
x: Nat
x
=>
x: Nat
x
+
1: Nat
1
fun x => x + 2 : Nat Nat
λ
x: Nat
x
=>
x: Nat
x
+
2: Nat
2
fun x => if x = 1 then "yes" else "no" : Nat String
fun
x: Nat
x
=> if
x: Nat
x
=
1: Nat
1
then
"yes": String
"yes"
else
"no": String
"no"
[1, 2, 3] : List Nat
([
1: Nat
1
,
2: Nat
2
,
3: Nat
3
] :
List: Type → Type
List
Nat: Type
Nat
)
#[1, 2, 3] : Array Nat
(#[
1: Nat
1
,
2: Nat
2
,
3: Nat
3
] :
Array: Type → Type
Array
Nat: Type
Nat
) def
isOne: Nat → String
isOne
(
x: Nat
x
:
Nat: Type
Nat
) :
String: Type
String
:= if
x: Nat
x
=
1: Nat
1
then
"yes": String
"yes"
else
"no": String
"no"
isOne (x : Nat) : String
isOne: Nat → String
isOne
def isOne : Nat String := fun x => if x = 1 then "yes" else "no"
isOne: Nat → String
isOne
2 + 2 < 5 isOne 3 = "no" : Prop
2: Nat
2
+
2: Nat
2
<
5: Nat
5
isOne: Nat → String
isOne
3: Nat
3
=
"no": String
"no"
def
Fermat_statement: Prop
Fermat_statement
:
Prop: Type
Prop
:=
a: Nat
a
b: Nat
b
c: Nat
c
n: Nat
n
:
Nat: Type
Nat
,
a: Nat
a
*
b: Nat
b
*
c: Nat
c
0: Nat
0
n: Nat
n
>
2: Nat
2
a: Nat
a
^
n: Nat
n
+
b: Nat
b
^
n: Nat
n
c: Nat
c
^
n: Nat
n
Fermat_statement : Prop
Fermat_statement: Prop
Fermat_statement
theorem
two_plus_two_is_four: 2 + 2 = 4
two_plus_two_is_four
:
2: Nat
2
+
2: Nat
2
=
4: Nat
4
:=
rfl: ∀ {α : Type} {a : α}, a = a
rfl
theorem
Warning: declaration uses 'sorry'
:
Fermat_statement: Prop
Fermat_statement
:=
sorry: Fermat_statement
sorry

3.2. Using Lean as a functional programming language

def 
printExample: IO Unit
printExample
:
IO: Type → Type
IO
Unit: Type
Unit
:= do
IO.println: {α : Type} → [inst : ToString α] → α → IO Unit
IO.println
"hello": String
"hello"
IO.println: {α : Type} → [inst : ToString α] → α → IO Unit
IO.println
"world": String
"world"
hello world
printExample: IO Unit
printExample
def
factorial: Nat → Nat
factorial
:
Nat: Type
Nat
Nat: Type
Nat
|
0: Nat
0
=>
1: Nat
1
| (
n: Nat
n
+ 1) => (
n: Nat
n
+
1: Nat
1
) *
factorial: Nat → Nat
factorial
n: Nat
n
3628800
factorial: Nat → Nat
factorial
10: Nat
10
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
factorial: Nat → Nat
factorial
100: Nat
100
def
hanoi: Nat → Nat → Nat → Nat → IO Unit
hanoi
(
numPegs: Nat
numPegs
start: Nat
start
finish: Nat
finish
aux: Nat
aux
:
Nat: Type
Nat
) :
IO: Type → Type
IO
Unit: Type
Unit
:= match
numPegs: Nat
numPegs
with |
0: Nat
0
=>
pure: {f : Type → Type} → [self : Pure f] → {α : Type} → α → f α
pure
(): Unit
()
|
n: Nat
n
+ 1 => do
hanoi: Nat → Nat → Nat → Nat → IO Unit
hanoi
n: Nat
n
start: Nat
start
aux: Nat
aux
finish: Nat
finish
IO.println: {α : Type} → [inst : ToString α] → α → IO Unit
IO.println
s!"Move disk {
n: Nat
n
+
1: Nat
1
} from peg {
start: Nat
start
} to peg {
finish: Nat
finish
}"
hanoi: Nat → Nat → Nat → Nat → IO Unit
hanoi
n: Nat
n
aux: Nat
aux
finish: Nat
finish
start: Nat
start
Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 3 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 4 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 3 from peg 2 to peg 3 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 5 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 3 from peg 3 to peg 1 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 4 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 3 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 6 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 3 from peg 2 to peg 3 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 4 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 3 from peg 3 to peg 1 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 5 from peg 2 to peg 3 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 3 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 4 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 3 from peg 2 to peg 3 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 7 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 3 from peg 3 to peg 1 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 4 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 3 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 5 from peg 3 to peg 1 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 3 from peg 2 to peg 3 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 4 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 3 from peg 3 to peg 1 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 6 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 3 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 4 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 3 from peg 2 to peg 3 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 5 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 3 from peg 3 to peg 1 Move disk 1 from peg 2 to peg 3 Move disk 2 from peg 2 to peg 1 Move disk 1 from peg 3 to peg 1 Move disk 4 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2 Move disk 2 from peg 1 to peg 3 Move disk 1 from peg 2 to peg 3 Move disk 3 from peg 1 to peg 2 Move disk 1 from peg 3 to peg 1 Move disk 2 from peg 3 to peg 2 Move disk 1 from peg 1 to peg 2
hanoi: Nat → Nat → Nat → Nat → IO Unit
hanoi
7: Nat
7
1: Nat
1
2: Nat
2
3: Nat
3
def
addNums: List Nat → Nat
addNums
:
List: Type → Type
List
Nat: Type
Nat
Nat: Type
Nat
| [] =>
0: Nat
0
|
a: Nat
a
::
as: List Nat
as
=>
a: Nat
a
+
addNums: List Nat → Nat
addNums
as: List Nat
as
21
addNums: List Nat → Nat
addNums
[
0: Nat
0
,
1: Nat
1
,
2: Nat
2
,
3: Nat
3
,
4: Nat
4
,
5: Nat
5
,
6: Nat
6
] section open List
[0, 1, 2, 3, 4, 5, 6]
range: Nat → List Nat
range
7: Nat
7
21
addNums: List Nat → Nat
addNums
(
range: Nat → List Nat
range
7: Nat
7
)
21
addNums: List Nat → Nat
addNums
$
range: Nat → List Nat
range
7: Nat
7
[3, 4, 5, 6, 7, 8, 9]
map: {α β : Type} → (α → β) → List α → List β
map
(fun
x: Nat
x
=>
x: Nat
x
+
3: Nat
3
) $
range: Nat → List Nat
range
7: Nat
7
[3, 4, 5, 6, 7, 8, 9]
map: {α β : Type} → (α → β) → List α → List β
map
(. + 3): Nat → Nat
(. + 3)
$
range: Nat → List Nat
range
7: Nat
7
21
foldl: {α β : Type} → (α → β → α) → α → List β → α
foldl
(. + .): Nat → Nat → Nat
(. + .)
0: Nat
0
$
range: Nat → List Nat
range
7: Nat
7
fun x x_1 => x + x_1 : (x : ?m.3461) (x_1 : ?m.3469 x) ?m.3470 x x_1
(. + .): (x : ?m.3461) → (x_1 : ?m.3469 x) → ?m.3470 x x_1
(. + .)
end partial def
gcd: Nat → Nat → Nat
gcd
m: Nat
m
n: Nat
n
:= if
n: Nat
n
=
0: Nat
0
then
m: Nat
m
else
gcd: Nat → Nat → Nat
gcd
n: Nat
n
(
m: Nat
m
%
n: Nat
n
)

3.3. Inductive data types in Lean

section

inductive 
BinTree: Type
BinTree
|
empty: BinTree
empty
:
BinTree: Type
BinTree
|
node: BinTree → BinTree → BinTree
node
:
BinTree: Type
BinTree
BinTree: Type
BinTree
BinTree: Type
BinTree
deriving
Repr: Type u → Type u
Repr
,
DecidableEq: Sort u → Sort (max 1 u)
DecidableEq
,
Inhabited: Sort u → Sort (max 1 u)
Inhabited
open BinTree
BinTree.node (BinTree.empty) (BinTree.node (BinTree.empty) (BinTree.empty))
node: BinTree → BinTree → BinTree
node
empty: BinTree
empty
(
node: BinTree → BinTree → BinTree
node
empty: BinTree
empty
empty: BinTree
empty
) def
size: BinTree → Nat
size
:
BinTree: Type
BinTree
Nat: Type
Nat
|
empty: BinTree
empty
=>
0: Nat
0
|
node: BinTree → BinTree → BinTree
node
a: BinTree
a
b: BinTree
b
=>
1: Nat
1
+
size: BinTree → Nat
size
a: BinTree
a
+
size: BinTree → Nat
size
b: BinTree
b
def
depth: BinTree → Nat
depth
:
BinTree: Type
BinTree
Nat: Type
Nat
|
empty: BinTree
empty
=>
0: Nat
0
|
node: BinTree → BinTree → BinTree
node
a: BinTree
a
b: BinTree
b
=>
1: Nat
1
+
Nat.max: Nat → Nat → Nat
Nat.max
(
depth: BinTree → Nat
depth
a: BinTree
a
) (
depth: BinTree → Nat
depth
b: BinTree
b
) def
example_tree: BinTree
example_tree
:=
node: BinTree → BinTree → BinTree
node
(
node: BinTree → BinTree → BinTree
node
empty: BinTree
empty
empty: BinTree
empty
) (
node: BinTree → BinTree → BinTree
node
empty: BinTree
empty
(
node: BinTree → BinTree → BinTree
node
empty: BinTree
empty
empty: BinTree
empty
))
4
size: BinTree → Nat
size
example_tree: BinTree
example_tree
3
depth: BinTree → Nat
depth
example_tree: BinTree
example_tree
end

3.4. Using Lean as an imperative programming language

def 
isPrime: Nat → Bool
isPrime
(
n: Nat
n
:
Nat: Type
Nat
) :
Bool: Type
Bool
:=
Id.run: {α : Type} → Id α → α
Id.run
do if
n: Nat
n
<
2: Nat
2
then
false: Bool
false
else for
i: Nat
i
in [
2: Nat
2
:
n: Nat
n
] do if
n: Nat
n
%
i: Nat
i
=
0: Nat
0
then return
false: Bool
false
if
i: Nat
i
*
i: Nat
i
>
n: Nat
n
then return
true: Bool
true
true: Bool
true
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973]
(
List.range: Nat → List Nat
List.range
10000: Nat
10000
).
filter: {α : Type} → (α → Bool) → List α → List α
filter
isPrime: Nat → Bool
isPrime
def
primes: Nat → Array Nat
primes
(
n: Nat
n
:
Nat: Type
Nat
) :
Array: Type → Type
Array
Nat: Type
Nat
:=
Id.run: {α : Type} → Id α → α
Id.run
do let mut
result: Array Nat
result
:=
#[]: Array Nat
#[]
for
i: Nat
i
in [
2: Nat
2
:
n: Nat
n
] do if
isPrime: Nat → Bool
isPrime
i: Nat
i
then
result: Array Nat
result
:=
result: Array Nat
result
.
push: {α : Type} → Array α → α → Array α
push
i: Nat
i
result: Array Nat
result
1229
(
primes: Nat → Array Nat
primes
10000: Nat
10000
).
size: {α : Type} → Array α → Nat
size

5. Implementing Propositional Logic

https://avigad.github.io/lamr/implementing_propositional_logic.html

5.1. Syntax

An atomic formula is a variable or one of the constants ⊤ or ⊥. A literal is an atomic formula or a negated atomic formula.

The set of propositional formulas in negation normal form (NNF) is generated inductively as follows:

Each literal is in negation normal form.

If A and B are in negation normal form, then so are A ∧ B and A ∨ B.

Proposition

Every propositional formula is equivalent to one in negation normal form.

Proof

First use the identities A ↔ B ≡ (A → B) ∧ (B → A) and A → B ≡ ¬A ∧ B to get rid of ≡ and →. Then use De Morgan’s laws together with ¬¬A ≡ A to push negations down to the atomic formulas.

section Props

inductive 
PropForm: Type
PropForm
|
tr: PropForm
tr
:
PropForm: Type
PropForm
|
fls: PropForm
fls
:
PropForm: Type
PropForm
|
var: String → PropForm
var
:
String: Type
String
PropForm: Type
PropForm
|
conj: PropForm → PropForm → PropForm
conj
:
PropForm: Type
PropForm
PropForm: Type
PropForm
PropForm: Type
PropForm
|
disj: PropForm → PropForm → PropForm
disj
:
PropForm: Type
PropForm
PropForm: Type
PropForm
PropForm: Type
PropForm
|
impl: PropForm → PropForm → PropForm
impl
:
PropForm: Type
PropForm
PropForm: Type
PropForm
PropForm: Type
PropForm
|
neg: PropForm → PropForm
neg
:
PropForm: Type
PropForm
PropForm: Type
PropForm
|
biImpl: PropForm → PropForm → PropForm
biImpl
:
PropForm: Type
PropForm
PropForm: Type
PropForm
PropForm: Type
PropForm
deriving
Repr: Type u → Type u
Repr
,
DecidableEq: Sort u → Sort (max 1 u)
DecidableEq
open PropForm
((var "p").conj (var "q")).impl (var "r") : PropForm
(
impl: PropForm → PropForm → PropForm
impl
(
conj: PropForm → PropForm → PropForm
conj
(
var: String → PropForm
var
"p": String
"p"
) (
var: String → PropForm
var
"q": String
"q"
)) (
var: String → PropForm
var
"r": String
"r"
)) namespace PropForm declare_syntax_cat propform syntax "prop!{"
propform: Lean.Parser.Category
propform
"}" :
term: Lean.Parser.Category
term
syntax:max ident :
propform: Lean.Parser.Category
propform
syntax "⊤" :
propform: Lean.Parser.Category
propform
syntax "⊥" :
propform: Lean.Parser.Category
propform
syntax:35
propform:36: Lean.Parser.Category
propform:36
" ∧ "
propform: Lean.Parser.Category
propform
:35 :
propform: Lean.Parser.Category
propform
syntax:30
propform:31: Lean.Parser.Category
propform:31
" ∨ "
propform: Lean.Parser.Category
propform
:30 :
propform: Lean.Parser.Category
propform
syntax:20
propform:21: Lean.Parser.Category
propform:21
" → "
propform: Lean.Parser.Category
propform
:20 :
propform: Lean.Parser.Category
propform
syntax:20
propform:21: Lean.Parser.Category
propform:21
" ↔ "
propform: Lean.Parser.Category
propform
:20 :
propform: Lean.Parser.Category
propform
syntax:max "¬ "
propform: Lean.Parser.Category
propform
:40 :
propform: Lean.Parser.Category
propform
syntax:max "("
propform: Lean.Parser.Category
propform
")" :
propform: Lean.Parser.Category
propform
macro_rules | `(prop!{$
p: Lean.TSyntax `ident
p
:ident}) => `(PropForm.var $(
Lean.quote: {α : Type} → {k : optParam Lean.SyntaxNodeKind `term} → [self : Lean.Quote α k] → α → Lean.TSyntax k
Lean.quote
p: Lean.TSyntax `ident
p
.
getId: Lean.Ident → Lean.Name
getId
.
toString: Lean.Name → optParam Bool true → String
toString
)) | `(prop!{}) =>
`(ProfForm.tr): Lean.MacroM Lean.Syntax
`(ProfForm.tr)
| `(prop!{}) =>
`(ProfForm.fls): Lean.MacroM Lean.Syntax
`(ProfForm.fls)
| `(prop!{¬ $
p: Lean.TSyntax `propform
p
}) => `(PropForm.neg prop!{$
p: Lean.TSyntax `propform
p
}) | `(prop!{$
p: Lean.TSyntax `propform
p
$
q: Lean.TSyntax `propform
q
}) => `(PropForm.conj prop!{$
p: Lean.TSyntax `propform
p
} prop!{$
q: Lean.TSyntax `propform
q
}) | `(prop!{$
p: Lean.TSyntax `propform
p
$
q: Lean.TSyntax `propform
q
}) => `(PropForm.disj prop!{$
p: Lean.TSyntax `propform
p
} prop!{$
q: Lean.TSyntax `propform
q
}) | `(prop!{$
p: Lean.TSyntax `propform
p
$
q: Lean.TSyntax `propform
q
}) => `(PropForm.impl prop!{$
p: Lean.TSyntax `propform
p
} prop!{$
q: Lean.TSyntax `propform
q
}) | `(prop!{$
p: Lean.TSyntax `propform
p
$
q: Lean.TSyntax `propform
q
}) => `(PropForm.biImpl prop!{$
p: Lean.TSyntax `propform
p
} prop!{$
q: Lean.TSyntax `propform
q
}) | `(prop!{($
p: Lean.TSyntax `propform
p
:
propform: Lean.Parser.Category
propform
)}) => `(prop!{$
p: Lean.TSyntax `propform
p
}) private def
toString: PropForm → String
toString
:
PropForm: Type
PropForm
String: Type
String
|
var: String → PropForm
var
s: String
s
=>
s: String
s
|
tr: PropForm
tr
=>
"⊤": String
"⊤"
|
fls: PropForm
fls
=>
"⊥": String
"⊥"
|
neg: PropForm → PropForm
neg
p: PropForm
p
=> s!"(¬ {
toString: PropForm → String
toString
p: PropForm
p
})" |
conj: PropForm → PropForm → PropForm
conj
p: PropForm
p
q: PropForm
q
=> s!"({
toString: PropForm → String
toString
p: PropForm
p
} {
toString: PropForm → String
toString
q: PropForm
q
})" |
disj: PropForm → PropForm → PropForm
disj
p: PropForm
p
q: PropForm
q
=> s!"({
toString: PropForm → String
toString
p: PropForm
p
} {
toString: PropForm → String
toString
q: PropForm
q
})" |
impl: PropForm → PropForm → PropForm
impl
p: PropForm
p
q: PropForm
q
=> s!"({
toString: PropForm → String
toString
p: PropForm
p
} {
toString: PropForm → String
toString
q: PropForm
q
})" |
biImpl: PropForm → PropForm → PropForm
biImpl
p: PropForm
p
q: PropForm
q
=> s!"({
toString: PropForm → String
toString
p: PropForm
p
} {
toString: PropForm → String
toString
q: PropForm
q
})"
instance: ToString PropForm
instance
:
ToString: Type → Type
ToString
PropForm: Type
PropForm
:=
PropForm.toString: PropForm → String
PropForm.toString
end PropForm
((var "p").conj (var "q")).impl (((var "r").disj (var "p").neg).impl (var "q")) : PropForm
prop!{p ∧ q → (r ∨ ¬ p) → q}: PropForm
prop!{
prop!{p ∧ q → (r ∨ ¬ p) → q}: PropForm
p q (r ¬ p) q}
PropForm.impl (PropForm.conj (PropForm.var "p") (PropForm.var "q")) (PropForm.impl (PropForm.disj (PropForm.var "r") (PropForm.neg (PropForm.var "p"))) (PropForm.var "q"))
prop!{p ∧ q → (r ∨ ¬ p) → q}: PropForm
prop!{
prop!{p ∧ q → (r ∨ ¬ p) → q}: PropForm
p q (r ¬ p) q}
((var "p").conj ((var "q").conj (var "r"))).impl (var "p") : PropForm
prop!{p ∧ q ∧ r → p}: PropForm
prop!{
prop!{p ∧ q ∧ r → p}: PropForm
p q r p}
def
propExample: PropForm
propExample
:=
prop!{p ∧ q → r ∧ p ∨ ¬ s1 → s2 }: PropForm
prop!{
prop!{p ∧ q → r ∧ p ∨ ¬ s1 → s2 }: PropForm
p q r p ¬ s1 s2 }

Minimal enhancement for List related examples:

namespace List

def 
insert': {α : Type u_1} → [inst : DecidableEq α] → α → List α → List α
insert'
[
DecidableEq: Type u_1 → Type u_1
DecidableEq
α: Type u_1
α
] (
a: α
a
:
α: Type u_1
α
) (
l: List α
l
:
List: Type u_1 → Type u_1
List
α: Type u_1
α
) :
List: Type u_1 → Type u_1
List
α: Type u_1
α
:= if
a: α
a
l: List α
l
then
l: List α
l
else
a: α
a
::
l: List α
l
protected def
union: {α : Type u_1} → [inst : DecidableEq α] → List α → List α → List α
union
[
DecidableEq: Type u_1 → Type u_1
DecidableEq
α: Type u_1
α
] (
l₁: List α
l₁
l₂: List α
l₂
:
List: Type u_1 → Type u_1
List
α: Type u_1
α
) :
List: Type u_1 → Type u_1
List
α: Type u_1
α
:=
foldr: {α β : Type u_1} → (α → β → β) → β → List α → β
foldr
insert': {α : Type u_1} → [inst : DecidableEq α] → α → List α → List α
insert'
l₂: List α
l₂
l₁: List α
l₁
end List namespace PropForm def
complexity: PropForm → Nat
complexity
:
PropForm: Type
PropForm
Nat: Type
Nat
|
var: String → PropForm
var
_ =>
0: Nat
0
|
tr: PropForm
tr
=>
0: Nat
0
|
fls: PropForm
fls
=>
0: Nat
0
|
neg: PropForm → PropForm
neg
A: PropForm
A
=>
complexity: PropForm → Nat
complexity
A: PropForm
A
+
1: Nat
1
|
conj: PropForm → PropForm → PropForm
conj
A: PropForm
A
B: PropForm
B
=>
complexity: PropForm → Nat
complexity
A: PropForm
A
+
complexity: PropForm → Nat
complexity
B: PropForm
B
+
1: Nat
1
|
disj: PropForm → PropForm → PropForm
disj
A: PropForm
A
B: PropForm
B
=>
complexity: PropForm → Nat
complexity
A: PropForm
A
+
complexity: PropForm → Nat
complexity
B: PropForm
B
+
1: Nat
1
|
impl: PropForm → PropForm → PropForm
impl
A: PropForm
A
B: PropForm
B
=>
complexity: PropForm → Nat
complexity
A: PropForm
A
+
complexity: PropForm → Nat
complexity
B: PropForm
B
+
1: Nat
1
|
biImpl: PropForm → PropForm → PropForm
biImpl
A: PropForm
A
B: PropForm
B
=>
complexity: PropForm → Nat
complexity
A: PropForm
A
+
complexity: PropForm → Nat
complexity
B: PropForm
B
+
1: Nat
1
def
depth: PropForm → Nat
depth
:
PropForm: Type
PropForm
Nat: Type
Nat
|
var: String → PropForm
var
_ =>
0: Nat
0
|
tr: PropForm
tr
=>
0: Nat
0
|
fls: PropForm
fls
=>
0: Nat
0
|
neg: PropForm → PropForm
neg
A: PropForm
A
=>
depth: PropForm → Nat
depth
A: PropForm
A
+
1: Nat
1
|
conj: PropForm → PropForm → PropForm
conj
A: PropForm
A
B: PropForm
B
=>
Nat.max: Nat → Nat → Nat
Nat.max
(
depth: PropForm → Nat
depth
A: PropForm
A
) (
depth: PropForm → Nat
depth
B: PropForm
B
) +
1: Nat
1
|
disj: PropForm → PropForm → PropForm
disj
A: PropForm
A
B: PropForm
B
=>
Nat.max: Nat → Nat → Nat
Nat.max
(
depth: PropForm → Nat
depth
A: PropForm
A
) (
depth: PropForm → Nat
depth
B: PropForm
B
) +
1: Nat
1
|
impl: PropForm → PropForm → PropForm
impl
A: PropForm
A
B: PropForm
B
=>
Nat.max: Nat → Nat → Nat
Nat.max
(
depth: PropForm → Nat
depth
A: PropForm
A
) (
depth: PropForm → Nat
depth
B: PropForm
B
) +
1: Nat
1
|
biImpl: PropForm → PropForm → PropForm
biImpl
A: PropForm
A
B: PropForm
B
=>
Nat.max: Nat → Nat → Nat
Nat.max
(
depth: PropForm → Nat
depth
A: PropForm
A
) (
depth: PropForm → Nat
depth
B: PropForm
B
) +
1: Nat
1
def
vars: PropForm → List String
vars
:
PropForm: Type
PropForm
List: Type → Type
List
String: Type
String
|
var: String → PropForm
var
s: String
s
=> [
s: String
s
] |
tr: PropForm
tr
=>
[]: List String
[]
|
fls: PropForm
fls
=>
[]: List String
[]
|
neg: PropForm → PropForm
neg
A: PropForm
A
=>
vars: PropForm → List String
vars
A: PropForm
A
|
conj: PropForm → PropForm → PropForm
conj
A: PropForm
A
B: PropForm
B
=> (
vars: PropForm → List String
vars
A: PropForm
A
).
union: {α : Type} → [inst : DecidableEq α] → List α → List α → List α
union
(
vars: PropForm → List String
vars
B: PropForm
B
) |
disj: PropForm → PropForm → PropForm
disj
A: PropForm
A
B: PropForm
B
=> (
vars: PropForm → List String
vars
A: PropForm
A
).
union: {α : Type} → [inst : DecidableEq α] → List α → List α → List α
union
(
vars: PropForm → List String
vars
B: PropForm
B
) |
impl: PropForm → PropForm → PropForm
impl
A: PropForm
A
B: PropForm
B
=> (
vars: PropForm → List String
vars
A: PropForm
A
).
union: {α : Type} → [inst : DecidableEq α] → List α → List α → List α
union
(
vars: PropForm → List String
vars
B: PropForm
B
) |
biImpl: PropForm → PropForm → PropForm
biImpl
A: PropForm
A
B: PropForm
B
=> (
vars: PropForm → List String
vars
A: PropForm
A
).
union: {α : Type} → [inst : DecidableEq α] → List α → List α → List α
union
(
vars: PropForm → List String
vars
B: PropForm
B
) end PropForm

5.2. Semantics

-- Minimal implementation for PropAssignment examples
def 
PropAssignment: Type
PropAssignment
:=
List: Type → Type
List
(
String: Type
String
×
Bool: Type
Bool
) namespace PropAssignment def
mk: List (String × Bool) → PropAssignment
mk
(
vars: List (String × Bool)
vars
:
List: Type → Type
List
(
String: Type
String
×
Bool: Type
Bool
)) :
PropAssignment: Type
PropAssignment
:=
vars: List (String × Bool)
vars
def
eval?: PropAssignment → String → Option Bool
eval?
(
τ: PropAssignment
τ
:
PropAssignment: Type
PropAssignment
) (
var: String
var
:
String: Type
String
) :
Option: Type → Type
Option
Bool: Type
Bool
:=
Id.run: {α : Type} → Id α → α
Id.run
do let
τ: List (String × Bool)
τ
:
List: Type → Type
List
_: Type
_
:=
τ: PropAssignment
τ
for (
k: String
k
,
v: Bool
v
) in
τ: List (String × Bool)
τ
do if
k: String
k
==
var: String
var
then return
some: {α : Type} → α → Option α
some
v: Bool
v
return
none: {α : Type} → Option α
none
def
eval: PropAssignment → String → Bool
eval
(
τ: PropAssignment
τ
:
PropAssignment: Type
PropAssignment
) (
var: String
var
:
String: Type
String
) :
Bool: Type
Bool
:=
τ: PropAssignment
τ
.
eval?: PropAssignment → String → Option Bool
eval?
var: String
var
|>.
getD: {α : Type} → Option α → α → α
getD
false: Bool
false
end PropAssignment def
PropForm.eval: PropAssignment → PropForm → Bool
PropForm.eval
(
v: PropAssignment
v
:
PropAssignment: Type
PropAssignment
) :
PropForm: Type
PropForm
Bool: Type
Bool
|
var: String → PropForm
var
s: String
s
=>
v: PropAssignment
v
.
eval: PropAssignment → String → Bool
eval
s: String
s
|
tr: PropForm
tr
=>
true: Bool
true
|
fls: PropForm
fls
=>
false: Bool
false
|
neg: PropForm → PropForm
neg
A: PropForm
A
=> !(
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
A: PropForm
A
) |
conj: PropForm → PropForm → PropForm
conj
A: PropForm
A
B: PropForm
B
=> (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
A: PropForm
A
) && (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
B: PropForm
B
) |
disj: PropForm → PropForm → PropForm
disj
A: PropForm
A
B: PropForm
B
=> (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
A: PropForm
A
) || (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
B: PropForm
B
) |
impl: PropForm → PropForm → PropForm
impl
A: PropForm
A
B: PropForm
B
=> !(
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
A: PropForm
A
) || (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
B: PropForm
B
) |
biImpl: PropForm → PropForm → PropForm
biImpl
A: PropForm
A
B: PropForm
B
=> (!(
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
A: PropForm
A
) || (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
B: PropForm
B
)) && (!(
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
B: PropForm
B
) || (
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
A: PropForm
A
))
true
let
v: PropAssignment
v
:=
PropAssignment.mk: List (String × Bool) → PropAssignment
PropAssignment.mk
[(
"p": String
"p"
,
true: Bool
true
), (
"q": String
"q"
,
true: Bool
true
), (
"r": String
"r"
,
true: Bool
true
)]
prop!{p ∧ q ∧ r → p}: PropForm
prop!{
prop!{p ∧ q ∧ r → p}: PropForm
p q r p}
.
eval: PropAssignment → PropForm → Bool
eval
v: PropAssignment
v
end Props