Advanced example showcasing the power of dependent types for compile-time guarantees.
-- Only works on non-empty vectors
safeHead : Vect (S n) a -> a
-- Bounded indexing (impossible to go out of bounds)
safeIndex : Fin n -> Vect n a -> a
-- Length tracking in types
safeTake : (n : Nat) -> Vect (n + m) a -> Vect n a-- Matrix with compile-time dimensions
Matrix : Nat -> Nat -> Type -> Type
-- Type ensures dimensions match!
matAdd : Matrix r c Int -> Matrix r c Int -> Matrix r c IntAll type-level guarantees become runtime checks:
def safe_head(vec: List[T]) -> T:
"""Idris2 type: Vect (S n) a -> a"""
assert len(vec) >= 1, "requires non-empty vector"
return vec[0]
def mat_add(mat1: Matrix, mat2: Matrix) -> Matrix:
"""Idris2 type: Matrix r c Int -> Matrix r c Int -> Matrix r c Int"""
assert mat1.rows == mat2.rows # Dimension check
assert mat1.cols == mat2.cols
# ...def test_safe_head_rejects_empty():
"""Type: Vect (S n) requires non-empty"""
with pytest.raises(AssertionError):
safe_head([]) # Type prevents this!@given(n=st.integers(0, 50), m=st.integers(0, 50))
def test_safe_take_length_property(n, m):
"""Type: Vect (n + m) → Vect n"""
vec = list(range(n + m))
result = safe_take(n, vec)
assert len(result) == n # Always true!def test_matches_idris2_output():
"""Verify Python matches Idris2 exactly"""
assert safe_head([1,2,3,4,5]) == 1
assert safe_take(3, [1,2,3,4,5]) == [1,2,3]idris2 -o safelist SafeList.idr
./build/exec/safelistOutput:
=== Safe List Operations ===
"Head: 1"
"Index 0: 1"
...
✅ All operations completed safely!
python safe_list.pyOutput: (identical to Idris2!)
pytest test_safe_list.py -vResult: 45/45 tests passed ✅
| Idris2 Type Constraint | Python Runtime Check |
|---|---|
Vect (S n) (non-empty) |
assert len(vec) >= 1 |
Fin n (bounded index) |
assert 0 <= i < n |
Vect (n + m) (length guarantee) |
assert len(vec) >= n |
Matrix r c (dimensions) |
assert rows == r and cols == c |
Every type constraint becomes a test:
- Preconditions → tests that invalid inputs are rejected
- Postconditions → tests that outputs meet guarantees
- Invariants → property-based tests
These bugs are impossible in Idris2, and caught by tests in Python:
- ❌ Empty list passed to
head - ❌ Out-of-bounds array access
- ❌ Matrix dimension mismatch
- ❌ Taking more elements than available
- Read the Idris2 code - Notice how types prevent errors
- Compare with Python - See how assertions preserve guarantees
- Study the tests - Understand how types become test cases
- Experiment - Try breaking the code and see tests catch it!
- Vect (S n): Non-empty list at type level
- Fin n: Bounded natural numbers (indices)
- Dependent pairs: Values that depend on other values
- Type-level arithmetic:
n + min types - Phantom types: Dimensions in Matrix type
This example shows the full power of type-driven development!