Writing Technical Posts in Lean

Hello! This was generated from the Verso templates.

def fib : Nat Nat | 0 => 0 | 1 => 1 | n + 2 => fib n + fib (n + 1)

As expected, it maps natural numbers to natural numbers:

fib : Nat Nat#check fib
fib : Nat  Nat

The answers are as expected:

55#eval fib 10
55
610#eval fib 15
610

The #eval commands show the actual computed results. This naive recursive implementation isn't efficient for large numbers, but it clearly demonstrates the mathematical definition. When you see this code, you know it actually runs exactly as written—there's no risk of typos or inconsistencies between the explanation and implementation.

Proofs Don't Fib

Here are a couple of proofs that demonstrate Lean's verification capabilities using our Fibonacci function. First off, the Fibonacci sequence is non-decreasing. That is, F_{n} \le F_{n + 1}:

theorem fib_nondec : fib n fib (n + 1) := n:Natfib n fib (n + 1) fib 0 fib (0 + 1)n✝:Nata✝:fib n✝ fib (n✝ + 1)fib (n✝ + 1) fib (n✝ + 1 + 1) fib 0 fib (0 + 1)n✝:Nata✝:fib n✝ fib (n✝ + 1)fib (n✝ + 1) fib (n✝ + 1 + 1) All goals completed! 🐙

Furthermore, the sequence is strictly increasing after the first two elements. The first step is to show that for all positive n, F_n is positive:

@[Try these: [apply] [grind .] for pattern: [@LE.le `[Nat] `[instLENat] `[1] (fib #1)] [apply] [grind →] for pattern: [@LE.le `[Nat] `[instLENat] `[1] #1] [apply] [grind! .] for pattern: [fib #1]grind] theorem fib_pos : n > 0 fib n > 0 := n:Natn > 0 fib n > 0 induction n with 0 > 0 fib 0 > 0 All goals completed! 🐙 n':Natih:n' > 0 fib n' > 0n' + 1 > 0 fib (n' + 1) > 0 n':Natih:n' > 0 fib n' > 00 < fib (n' + 1) ih:0 > 0 fib 0 > 00 < fib (0 + 1)n✝:Natih:n✝ + 1 > 0 fib (n✝ + 1) > 00 < fib (n✝ + 1 + 1) ih:0 > 0 fib 0 > 00 < fib (0 + 1)n✝:Natih:n✝ + 1 > 0 fib (n✝ + 1) > 00 < fib (n✝ + 1 + 1) All goals completed! 🐙

Now, grind can use the lemma to show that fib is strictly increasing:

theorem fib_gt_1_inc : fib (n + 2) < fib (n + 3) := n:Natfib (n + 2) < fib (n + 3) fib (0 + 2) < fib (0 + 3)n✝:Nata✝:fib (n✝ + 2) < fib (n✝ + 3)fib (n✝ + 1 + 2) < fib (n✝ + 1 + 3) fib (0 + 2) < fib (0 + 3)n✝:Nata✝:fib (n✝ + 2) < fib (n✝ + 3)fib (n✝ + 1 + 2) < fib (n✝ + 1 + 3) All goals completed! 🐙

Additionally, every third element of the sequence is even. If a number n is even, then there exists some k such that n = 3k; the proof is by induction on k.

theorem fib_third_even : 3 n 2 fib n := n:Nat3 n 2 fib n n:Natk:Nathk:n = 3 * k2 fib n n:Natk:Nathk:n = 3 * k2 fib (3 * k) k:Nat2 fib (3 * k) 2 fib (3 * 0)n✝:Nata✝:2 fib (3 * n✝)2 fib (3 * (n✝ + 1)) 2 fib (3 * 0)n✝:Nata✝:2 fib (3 * n✝)2 fib (3 * (n✝ + 1)) All goals completed! 🐙

Moving Forward

Having executable code and verified proofs directly in blog posts eliminates the usual gap between explanation and implementation. The interactive features—like being able to hover over function names to see their types and documentation—make the reading experience more informative than “plain” code blocks. Furthermore, tactic proofs are difficult to read without intermediate proof states, so Verso makes these visible.

For more advanced users, Verso itself can be extended in Lean, which opens up interesting possibilities for custom blog functionality. I'm planning to explore some data structure implementations and more mathematical concepts in future posts.