Debugging & Troubleshooting
Learn essential techniques for understanding and fixing errors in Lean. From reading error messages to using #check and #eval, these tools will help you debug code effectively.
Reading Error Messages
Lean's error messages are detailed and helpful once you learn to read them. They typically include the location, what was expected, and what was found:
1-- Example error2def add (x : Nat) (y : Nat) : String := x + y3-- ERROR: type mismatch4-- x + y5-- has type6-- Nat7-- but is expected to have type8-- String910-- The fix: change return type or convert11def add' (x : Nat) (y : Nat) : Nat := x + y12def addStr (x : Nat) (y : Nat) : String := toString (x + y)Using #check
The #check command shows the type of any expression. Use it to understand what you're working with:
1-- Check types of values2#check 42 -- Nat3#check "hello" -- String4#check true -- Bool56-- Check types of functions7#check Nat.add -- Nat → Nat → Nat8#check List.map -- {α β : Type} → (α → β) → List α → List β910-- Check complex expressions11#check (fun x => x + 1) -- Nat → Nat12#check [1, 2, 3].map -- (Nat → β) → List β1314-- Check with explicit types15#check (42 : Int) -- Int16#check ([] : List String) -- List StringUsing #eval
#eval runs code and shows the result. Great for testing expressions interactively:
1-- Test computations2#eval 2 + 3 -- 53#eval [1, 2, 3].length -- 34#eval "hello".toUpper -- "HELLO"56-- Test functions7def double (n : Nat) := n * 28#eval double 5 -- 10910-- Test complex expressions11#eval [1, 2, 3].map (· * 2) |> List.sum -- 121213-- Can't eval functions that need IO14-- #eval IO.println "hi" -- Error15-- Use #eval do instead:16-- (Run in main or with IO.println disabled)Using #print
#print shows the full definition of a name. Useful for understanding library functions:
1-- See how things are defined2#print Nat.add3#print List.map4#print Bool56-- Great for understanding type class instances7#print instBEqNat -- How Nat equality worksCommon Errors and Fixes
Type Mismatch
1-- Problem: wrong type2-- def f : String := 4234-- Fix 1: Change the annotation5def f : Nat := 4267-- Fix 2: Convert the value8def g : String := toString 42Unknown Identifier
1-- Problem: name not in scope2-- #eval unknownFunction34-- Common causes:5-- 1. Typo in the name6-- 2. Missing import7-- 3. Wrong namespace89-- Fix: Check spelling, add import, or use full name10import Mathlib.Tactic -- Add import11open List in #eval head? [1, 2] -- Open namespaceFunction Expected
1-- Problem: applying non-function2-- #eval 42 5 -- Error: 42 is not a function34-- This often happens with missing parentheses5-- #eval add 1 2 3 -- If add takes 2 args, this is wrong67-- Fix: Check function arity and add parens8#eval (add 1 2) + 3Failed to Synthesize Instance
1-- Problem: type class instance not found2-- def eq [BEq α] (x y : α) := x == y3-- #eval eq (fun _ => 1) (fun _ => 1) -- No BEq for functions!45-- Fix: Use only types with the required instance6#eval (5 : Nat) == 5 -- Nat has BEq ✓Debugging Tactics: trace
In proofs, trace prints debug information:
1example : 2 + 2 = 4 := by2 trace "Before simp"3 simp4 trace "After simp" -- Won't run, goal is closedThe sorry Tactic
sorry lets you skip parts of a proof temporarily. Useful for exploring structure:
1-- Sketch a proof structure, fill in later2theorem complex_proof (n : Nat) : n + 0 = n ∧ 0 + n = n := by3 constructor4 · sorry -- First part5 · sorry -- Second part67-- Warning: sorry makes proofs invalid!8-- Lean shows a warning when sorry is usedsorry in production. It axiomatically assumes anything is true, which can lead to inconsistencies.Best Practices
- Use #check liberally — Type confusion is the #1 source of errors
- Test small pieces — Use #eval to test functions before using them
- Read error messages fully — They often contain the solution
- Use sorry to sketch — Then fill in one piece at a time
- Check imports — Many "unknown identifier" errors are missing imports
Fix the type error in this code:
1-- This has an error2-- def greet (name : String) : Nat := "Hello, " ++ name34-- Fixed version5def greet (name : String) : String := "Hello, " ++ name