docs: add comprehensive language documentation
Documentation structure inspired by Rust Book, Elm Guide, and others: Guide (10 chapters): - Introduction and setup - Basic types (Int, String, Bool, List, Option, Result) - Functions (closures, higher-order, composition) - Data types (ADTs, pattern matching, records) - Effects (the core innovation) - Handlers (patterns and techniques) - Modules (imports, exports, organization) - Error handling (Fail, Option, Result) - Standard library reference - Advanced topics (traits, generics, optimization) Reference: - Complete syntax reference Tutorials: - Calculator (parsing, evaluation, REPL) - Dependency injection (testing with effects) - Project ideas (16 projects by difficulty) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
331
docs/guide/04-data-types.md
Normal file
331
docs/guide/04-data-types.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# 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<T>
|
||||
|
||||
For optional values:
|
||||
|
||||
```lux
|
||||
type Option<T> =
|
||||
| Some(T)
|
||||
| None
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```lux
|
||||
fn safeDivide(a: Int, b: Int): Option<Int> =
|
||||
if b == 0 then None
|
||||
else Some(a / b)
|
||||
|
||||
fn showResult(opt: Option<Int>): 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<T, E>
|
||||
|
||||
For operations that can fail with an error:
|
||||
|
||||
```lux
|
||||
type Result<T, E> =
|
||||
| Ok(T)
|
||||
| Err(E)
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```lux
|
||||
fn parseAge(s: String): Result<Int, String> =
|
||||
// Simplified - assume we have a real parser
|
||||
if s == "42" then Ok(42)
|
||||
else Err("Invalid age: " + s)
|
||||
|
||||
fn handleAge(r: Result<Int, String>): String =
|
||||
match r {
|
||||
Ok(age) => "Age is " + toString(age),
|
||||
Err(msg) => "Error: " + msg
|
||||
}
|
||||
```
|
||||
|
||||
### List<T>
|
||||
|
||||
Lists are built-in but conceptually:
|
||||
|
||||
```lux
|
||||
type List<T> =
|
||||
| Nil
|
||||
| Cons(T, List<T>)
|
||||
```
|
||||
|
||||
Pattern match on lists:
|
||||
|
||||
```lux
|
||||
fn sum(nums: List<Int>): Int =
|
||||
match nums {
|
||||
[] => 0,
|
||||
[x, ...rest] => x + sum(rest)
|
||||
}
|
||||
|
||||
fn length<T>(list: List<T>): Int =
|
||||
match list {
|
||||
[] => 0,
|
||||
[_, ...rest] => 1 + length(rest)
|
||||
}
|
||||
```
|
||||
|
||||
## Recursive Types
|
||||
|
||||
Types can reference themselves:
|
||||
|
||||
```lux
|
||||
type Tree<T> =
|
||||
| Leaf(T)
|
||||
| Node(Tree<T>, Tree<T>)
|
||||
|
||||
fn sumTree(t: Tree<Int>): 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<Int, String> =
|
||||
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.
|
||||
Reference in New Issue
Block a user