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>
4.3 KiB
Chapter 1: Introduction to Lux
Welcome to Lux, a functional programming language where side effects are first-class citizens.
Why Lux?
Every program does more than compute. It reads files, makes network requests, prints output, handles errors. In most languages, these effects are invisible—a function's type doesn't tell you what it might do.
Lux changes this. Effects are:
- Visible in the type signature
- Controllable via handlers
- Composable without boilerplate
This isn't just academic. It means:
- Tests can swap real I/O for mocks—automatically
- Error handling is explicit, not exceptional
- Dependencies are injected through the type system
Installation
From Source (Cargo)
git clone https://github.com/your-org/lux
cd lux
cargo build --release
# Add to PATH
export PATH="$PATH:$(pwd)/target/release"
With Nix
# Enter development shell
nix develop
# Or build
nix build
./result/bin/lux
Verify Installation
$ lux --version
Lux 0.1.0
$ lux --help
Usage: lux [OPTIONS] [FILE]
Options:
-c, --check Type check without running
--lsp Start LSP server
--repl Start interactive REPL
-h, --help Print help
Your First Program
Create a file called hello.lux:
// hello.lux - Your first Lux program
fn main(): Unit with {Console} =
Console.print("Hello, Lux!")
let output = run main() with {}
Run it:
$ lux hello.lux
Hello, Lux!
Let's break this down:
The Function Signature
fn main(): Unit with {Console}
fn main()- A function namedmainwith no parameters: Unit- ReturnsUnit(likevoid)with {Console}- Uses the Console effect
That last part is key. The type tells us this function prints to the console. A function without with {...} is pure—it can only compute.
The Body
Console.print("Hello, Lux!")
Console.print is an effect operation. It's not a regular function—it's a request to the environment to print something.
Running Effects
let output = run main() with {}
The run ... with {} expression executes a computation with its effects. The {} means "use the default handlers for all effects." Console's default handler prints to stdout.
The REPL
Lux has an interactive mode:
$ lux
Lux v0.1.0 - Type :help for commands
>
Try some expressions:
> 1 + 2
3
> "Hello, " + "World"
"Hello, World"
> [1, 2, 3]
[1, 2, 3]
> List.map([1, 2, 3], fn(x: Int): Int => x * 2)
[2, 4, 6]
Define functions:
> fn square(x: Int): Int = x * x
<function>
> square(5)
25
> fn greet(name: String): Unit with {Console} = Console.print("Hi, " + name)
<function>
> run greet("Alice") with {}
Hi, Alice
REPL commands:
:help - Show help
:type e - Show type of expression
:quit - Exit REPL
:clear - Clear screen
A Slightly Bigger Program
Let's write a program that asks for your name:
// greet.lux
fn askName(): String with {Console} = {
Console.print("What's your name?")
Console.readLine()
}
fn main(): Unit with {Console} = {
let name = askName()
Console.print("Hello, " + name + "!")
}
let output = run main() with {}
$ lux greet.lux
What's your name?
> Alice
Hello, Alice!
Notice how:
askNamereturnsStringbut haswith {Console}because it does I/O- Both functions declare their effects
- The
runat the end provides the runtime
Pure vs Effectful
Here's the key insight. Compare:
// Pure - no effects, only computes
fn add(a: Int, b: Int): Int = a + b
// Effectful - uses Console
fn printSum(a: Int, b: Int): Unit with {Console} =
Console.print(toString(a + b))
You can call add from anywhere. But printSum can only be called from:
- Another function that declares
Console - Inside a
run ... with {}block
This is the effect discipline. Effects propagate up until handled.
What's Next
Now that you can run programs, let's learn:
- Chapter 2: Basic Types - Numbers, strings, booleans
- Chapter 3: Functions - Definitions, closures, composition
- Chapter 4: Data Types - ADTs and pattern matching
Or jump ahead to what makes Lux special:
- Chapter 5: Effects - The core innovation