Files
lux/docs/OVERVIEW.md
2026-02-13 02:57:01 -05:00

7.9 KiB

Lux Language Overview

What is Lux?

Lux is a statically-typed functional programming language with algebraic effects as a first-class feature. It makes side effects explicit, trackable, and testable.

What Can You Do With It?

Currently Working

// Functions with type inference
fn factorial(n: Int): Int =
    if n <= 1 then 1 else n * factorial(n - 1)

// Higher-order functions
fn apply(f: fn(Int): Int, x: Int): Int = f(x)
fn double(x: Int): Int = x * 2
let result = apply(double, 21)  // 42

// Lambdas and closures
let add = fn(a: Int, b: Int): Int => a + b
let addFive = fn(x: Int): Int => add(5, x)

// Pattern matching
fn describe(n: Int): String =
    match n {
        0 => "zero",
        1 => "one",
        _ => "many"
    }

// Records
let person = { name: "Alice", age: 30 }
let age = person.age

// Tuples
let point = (10, 20)

// Lists
let numbers = [1, 2, 3, 4, 5]

// Pipe operator
let result = 5 |> double |> addOne  // (5 * 2) + 1 = 11

// Built-in effects (Console, Fail)
Console.print("Hello, world!")

// Custom effects
effect Logger {
    fn log(level: String, msg: String): Unit
}

// Effect handlers
handler consoleLogger: Logger {
    fn log(level, msg) = Console.print("[" + level + "] " + msg)
}

// Running with handlers
fn greet(name: String): Unit with {Logger} =
    Logger.log("info", "Hello, " + name)

run greet("Alice") with { Logger = consoleLogger }

Standard Library (Built-in)

// List operations
List.map([1, 2, 3], fn(x: Int): Int => x * 2)    // [2, 4, 6]
List.filter([1, 2, 3, 4], fn(x: Int): Bool => x > 2)  // [3, 4]
List.fold([1, 2, 3], 0, fn(acc: Int, x: Int): Int => acc + x)  // 6
List.head([1, 2, 3])      // Some(1)
List.tail([1, 2, 3])      // Some([2, 3])
List.concat([1, 2], [3])  // [1, 2, 3]
List.reverse([1, 2, 3])   // [3, 2, 1]
List.length([1, 2, 3])    // 3
List.get([1, 2, 3], 0)    // Some(1)
List.range(0, 5)          // [0, 1, 2, 3, 4]

// String operations
String.split("a,b,c", ",")       // ["a", "b", "c"]
String.join(["a", "b"], "-")     // "a-b"
String.trim("  hello  ")         // "hello"
String.contains("hello", "ell")  // true
String.replace("hi", "i", "ey")  // "hey"
String.length("hello")           // 5
String.chars("hi")               // ['h', 'i']
String.lines("a\nb")             // ["a", "b"]

// Option operations
let x = Some(42)
let y = None
Option.map(x, fn(n: Int): Int => n * 2)  // Some(84)
Option.flatMap(x, fn(n: Int): Option<Int> => Some(n + 1))  // Some(43)
Option.getOrElse(y, 0)  // 0
Option.isSome(x)        // true
Option.isNone(y)        // true

// Result operations
let ok = Ok(42)
let err = Err("failed")
Result.map(ok, fn(n: Int): Int => n * 2)  // Ok(84)
Result.getOrElse(err, 0)  // 0
Result.isOk(ok)           // true
Result.isErr(err)         // true

// Utility functions
print("Hello")      // prints to stdout
toString(42)        // "42"
typeOf([1, 2, 3])   // "List"

Planned (Not Yet Implemented)

  • Schema Evolution: Versioned types with automatic migrations
  • Behavioral Types: Properties like is pure, is idempotent
  • Modules/Imports: Code organization
  • Compilation: Currently interpreter-only

Primary Use Cases

1. Learning Effect Systems

Lux is an excellent educational tool for understanding algebraic effects without the complexity of Haskell's monad transformers or the academic syntax of languages like Koka.

2. Testable Application Code

Effects make dependencies explicit. Swap handlers for testing:

// Production
run app() with { Database = postgres, Http = realHttp }

// Testing
run app() with { Database = mockDb, Http = mockHttp }

3. Domain Modeling

Explicit effects document what code can do:

fn processOrder(order: Order): Receipt with {Database, Email, Logger}
// ^ The signature tells you exactly what side effects this function performs

4. Prototyping

Quick iteration with type inference and a REPL.


Pros and Cons

Pros

Advantage Description
Explicit Effects Function signatures show what side effects are possible
Testability Swap effect handlers for mocking—no dependency injection frameworks
Type Safety Static types catch errors at compile time
Type Inference Write less type annotations, compiler figures it out
Clean Syntax ML-family inspired, minimal boilerplate
Pattern Matching Destructure data elegantly
Immutable by Default Easier to reason about
REPL Interactive development

Cons

Limitation Description
Interpreter Only No compilation to native/JS/WASM yet
No Modules Can't split code across files
Limited IO Only Console built-in, no file/network
No Generics Polymorphic functions not fully implemented
New Paradigm Effects require learning new concepts
Small Ecosystem No packages, libraries, or community
Early Stage Bugs likely, features incomplete

Complexity Assessment

Conceptual Complexity

Concept Difficulty Notes
Basic syntax Easy Similar to other ML-family languages
Functions Easy Standard functional style
Pattern matching Easy If you know any FP language
Type system Medium Hindley-Milner inference helps
Effects Medium New concept, but simpler than monads
Handlers Medium Requires understanding of continuations

Comparison to Other Languages

Language Complexity Comparison to Lux
Python Simpler No types, no effect tracking
TypeScript Similar Lux has effects, TS has larger ecosystem
Elm Similar Both pure FP, Lux has general effects
Haskell More Complex Monads harder than algebraic effects
Koka Similar Koka more academic, Lux more practical syntax
Rust More Complex Ownership adds significant complexity

Learning Curve

Beginner (1-2 hours):

  • Basic expressions, functions, let bindings
  • If/else, pattern matching
  • REPL usage

Intermediate (1-2 days):

  • Custom types and records
  • Higher-order functions
  • Built-in effects (Console)

Advanced (1 week):

  • Custom effect definitions
  • Effect handlers
  • Understanding when to use effects vs. regular functions

When to Use Lux

Good Fit

  • Learning algebraic effects
  • Prototyping with explicit effect tracking
  • Small tools where testability matters
  • Teaching functional programming concepts

Not a Good Fit (Yet)

  • Production applications (too early)
  • Performance-critical code (interpreter)
  • Large codebases (no modules)
  • Web development (no JS compilation)
  • Systems programming (no low-level control)

Example Session

$ cargo run
Lux v0.1.0
Type :help for help, :quit to exit

lux> let x = 42
lux> x * 2
84
lux> fn greet(name: String): Unit with {Console} = Console.print("Hello, " + name)
lux> greet("World")
Hello, World
()
lux> let nums = [1, 2, 3]
lux> nums
[1, 2, 3]
lux> :quit

Architecture

Source Code
    │
    ▼
┌─────────┐
│  Lexer  │  → Tokens
└─────────┘
    │
    ▼
┌─────────┐
│ Parser  │  → AST
└─────────┘
    │
    ▼
┌─────────────┐
│ Type Checker│  → Typed AST + Effect Tracking
└─────────────┘
    │
    ▼
┌─────────────┐
│ Interpreter │  → Values + Effect Handling
└─────────────┘

Future Roadmap

  1. Standard Library - List, String, Option utilities
  2. Module System - Import/export, namespaces
  3. JavaScript Backend - Run in browsers
  4. Schema Evolution - Versioned types
  5. Behavioral Types - is pure, is idempotent
  6. LSP Server - IDE support
  7. Package Manager - Share code