Zulip Chat Archive

Stream: new members

Topic: Need help with improving a basic Lean example


Rick van Oosterhout (Feb 04 2025 at 20:57):

I worked out a basic concept that I want to use to explain some of the concepts of dependent type theory, calculus of (inductive) constructions and Lean, using some analogies with Lego's. I came up with the following definitions and managed to set up a simple theorem and prove it. However, I would like to have some feedback from more experienced Lean users.

Mainly looking for tips to expand the analogy to explain other relevant topics, if you think I missed one. Besides, I would like to get any feedback on the Lean definitions and theorems, on how things could be simplified or clarified further. Any suggestions on my code are welcome, as I want to learn the best practices for Lean.

open Nat

-- Use natural numbers
abbrev  := Nat

-- Basic brick type
inductive Lego : Type
  | brick
  | plate

namespace Lego

-- Function that adds computation to the tower
def brickHeight : Lego  
  | brick => 3
  | plate => 1

#eval brickHeight plate
#eval brickHeight brick


-- Define the inductive type for a Lego Tower
inductive LegoTower : Type
  | base : LegoTower  -- Base case: base plate
  | stack : Lego  LegoTower  LegoTower  -- Inductive step: add a lego

namespace LegoTower

def t1 : LegoTower := base
def t2 : LegoTower := stack plate base
def t3 : LegoTower := stack plate (stack brick base)


-- Define a dependent type for a tower with exactly 'n' lego's
inductive nLegoTower :   Type
  | nBase : nLegoTower 0  -- A tower of height 0 (base case)
  | nStack : Lego  (nLegoTower n)  nLegoTower (n + 1)  -- Add a lego

namespace nLegoTower

-- Example of a tower with exactly 3 lego's
def nLegoTower3 : nLegoTower 3 := (nStack brick (nStack plate (nStack brick (nBase))))

def nToLegoTower {n: } : nLegoTower n  LegoTower
  | nBase => base
  | nStack br rest => stack br (nToLegoTower rest)


-- Tower height
def recTowerHeight (tower : LegoTower) :=
  match tower with
  | base => 0
  | stack br rest => brickHeight br + recTowerHeight rest

def towerHeight (tower : LegoTower) :  := recTowerHeight tower

#eval towerHeight t1
#eval towerHeight t2
#eval towerHeight t3

#eval towerHeight (nToLegoTower nLegoTower3)


-- Basic proof that 'towerHeight (nToLegoTower t) ≤ 3 * n'

-- Lemma that any brick ≤ 3
theorem brick_height_limit (b : Lego) : brickHeight b  3 := by
  induction b <;> (rw [brickHeight]; simp)

-- Lemma for the inductive step below
theorem n_tower_max_height_ind (n : ) (t : nLegoTower m) :
  towerHeight (nToLegoTower t)  3 * n  brickHeight b + towerHeight (nToLegoTower t)  3 * n + 3 := by
    intro h
    calc
      brickHeight b + towerHeight (nToLegoTower t)
         3 + towerHeight (nToLegoTower t) := by apply Nat.add_le_add_right (brick_height_limit b)
      _  3 + 3 * n := by apply Nat.add_le_add_left h
      _ = 3 * n + 3 := by rw [Nat.add_comm]

-- Complete proof
theorem n_tower_max_height (t : nLegoTower n) : towerHeight (nToLegoTower t)  3 * n := by
  induction t with
  | nBase =>
    -- Simplify case
    rw [nToLegoTower, towerHeight, recTowerHeight, Nat.mul_zero, Nat.le_zero_eq]
  | nStack b rt ih =>
    -- Move out brickheight b
    rw [nToLegoTower, towerHeight, recTowerHeight,  towerHeight, Nat.mul_add, Nat.mul_one]
    -- Solve using lemma
    exact n_tower_max_height_ind _ rt ih

Last updated: May 02 2025 at 03:31 UTC