# Chapter 4: Data Types Lux has algebraic data types (ADTs)—a powerful way to model data with variants and pattern matching. ## Defining Types ### Enums (Sum Types) A type that can be one of several variants: ```lux type Color = | Red | Green | Blue let c: Color = Red ``` ### Variants with Data Variants can carry data: ```lux type Shape = | Circle(Int) // radius | Rectangle(Int, Int) // width, height | Point let s1 = Circle(5) let s2 = Rectangle(10, 20) let s3 = Point ``` ### Named Fields For clarity, use record variants: ```lux type Person = | Person { name: String, age: Int } let alice = Person { name: "Alice", age: 30 } ``` ## Pattern Matching The `match` expression destructures data: ```lux fn colorName(c: Color): String = match c { Red => "red", Green => "green", Blue => "blue" } ``` ### Extracting Data ```lux fn area(s: Shape): Int = match s { Circle(r) => 3 * r * r, // Approximate π as 3 Rectangle(w, h) => w * h, Point => 0 } area(Circle(5)) // 75 area(Rectangle(4, 5)) // 20 ``` ### Exhaustiveness The compiler ensures you handle all cases: ```lux fn colorName(c: Color): String = match c { Red => "red", Green => "green" // Error: non-exhaustive pattern, missing Blue } ``` ### Wildcard Pattern Use `_` to match anything: ```lux fn isRed(c: Color): Bool = match c { Red => true, _ => false // Matches Green, Blue, anything else } ``` ### Guards Add conditions to patterns: ```lux fn classify(n: Int): String = match n { 0 => "zero", n if n > 0 => "positive", _ => "negative" } ``` ### Nested Patterns Match deep structures: ```lux type Expr = | Num(Int) | Add(Expr, Expr) | Mul(Expr, Expr) fn simplify(e: Expr): Expr = match e { Add(Num(0), x) => x, // 0 + x = x Add(x, Num(0)) => x, // x + 0 = x Mul(Num(0), _) => Num(0), // 0 * x = 0 Mul(_, Num(0)) => Num(0), // x * 0 = 0 Mul(Num(1), x) => x, // 1 * x = x Mul(x, Num(1)) => x, // x * 1 = x _ => e // No simplification } ``` ## Built-in ADTs ### Option For optional values: ```lux type Option = | Some(T) | None ``` Usage: ```lux fn safeDivide(a: Int, b: Int): Option = if b == 0 then None else Some(a / b) fn showResult(opt: Option): String = match opt { Some(n) => "Result: " + toString(n), None => "Cannot divide by zero" } showResult(safeDivide(10, 2)) // "Result: 5" showResult(safeDivide(10, 0)) // "Cannot divide by zero" ``` ### Result For operations that can fail with an error: ```lux type Result = | Ok(T) | Err(E) ``` Usage: ```lux fn parseAge(s: String): Result = // Simplified - assume we have a real parser if s == "42" then Ok(42) else Err("Invalid age: " + s) fn handleAge(r: Result): String = match r { Ok(age) => "Age is " + toString(age), Err(msg) => "Error: " + msg } ``` ### List Lists are built-in but conceptually: ```lux type List = | Nil | Cons(T, List) ``` Pattern match on lists: ```lux fn sum(nums: List): Int = match nums { [] => 0, [x, ...rest] => x + sum(rest) } fn length(list: List): Int = match list { [] => 0, [_, ...rest] => 1 + length(rest) } ``` ## Recursive Types Types can reference themselves: ```lux type Tree = | Leaf(T) | Node(Tree, Tree) fn sumTree(t: Tree): Int = match t { Leaf(n) => n, Node(left, right) => sumTree(left) + sumTree(right) } let tree = Node(Node(Leaf(1), Leaf(2)), Leaf(3)) sumTree(tree) // 6 ``` ## Type Aliases Give names to existing types: ```lux type UserId = Int type Username = String type UserMap = List<(UserId, Username)> ``` ## Records Anonymous record types: ```lux let point = { x: 10, y: 20 } point.x // 10 point.y // 20 // With type annotation type Point = { x: Int, y: Int } let p: Point = { x: 5, y: 10 } ``` ### Record Update Create new records based on existing ones: ```lux let p1 = { x: 10, y: 20 } let p2 = { ...p1, x: 15 } // { x: 15, y: 20 } ``` ## Practical Example: Expression Evaluator ```lux type Expr = | Num(Int) | Add(Expr, Expr) | Sub(Expr, Expr) | Mul(Expr, Expr) | Div(Expr, Expr) fn eval(e: Expr): Result = match e { Num(n) => Ok(n), Add(a, b) => { match (eval(a), eval(b)) { (Ok(x), Ok(y)) => Ok(x + y), (Err(e), _) => Err(e), (_, Err(e)) => Err(e) } }, Sub(a, b) => { match (eval(a), eval(b)) { (Ok(x), Ok(y)) => Ok(x - y), (Err(e), _) => Err(e), (_, Err(e)) => Err(e) } }, Mul(a, b) => { match (eval(a), eval(b)) { (Ok(x), Ok(y)) => Ok(x * y), (Err(e), _) => Err(e), (_, Err(e)) => Err(e) } }, Div(a, b) => { match (eval(a), eval(b)) { (Ok(_), Ok(0)) => Err("Division by zero"), (Ok(x), Ok(y)) => Ok(x / y), (Err(e), _) => Err(e), (_, Err(e)) => Err(e) } } } // (10 + 5) * 2 let expr = Mul(Add(Num(10), Num(5)), Num(2)) eval(expr) // Ok(30) // 10 / 0 let bad = Div(Num(10), Num(0)) eval(bad) // Err("Division by zero") ``` ## Summary | Concept | Syntax | Example | |---------|--------|---------| | Enum | `type T = \| A \| B` | `type Bool = \| True \| False` | | With data | `\| Variant(Type)` | `\| Some(Int)` | | Match | `match x { ... }` | `match opt { Some(n) => n, None => 0 }` | | Wildcard | `_` | `_ => "default"` | | Guard | `pattern if cond` | `n if n > 0 => "positive"` | | Record | `{ field: value }` | `{ x: 10, y: 20 }` | ## Next [Chapter 5: Effects](05-effects.md) - The core innovation of Lux.