style: auto-format example files with lux fmt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 06:52:44 -05:00
parent 8c90d5a8dc
commit 44ea1eebb0
54 changed files with 580 additions and 1483 deletions

View File

@@ -1,36 +1,19 @@
// Demonstrating behavioral properties in Lux
// Behavioral properties are compile-time guarantees about function behavior
//
// Expected output:
// add(5, 3) = 8
// factorial(5) = 120
// multiply(7, 6) = 42
// abs(-5) = 5
fn add(a: Int, b: Int): Int is pure = a + b
// A pure function - no side effects, same input always gives same output
fn add(a: Int, b: Int): Int is pure =
a + b
fn factorial(n: Int): Int is deterministic = if n <= 1 then 1 else n * factorial(n - 1)
// A deterministic function - same input always gives same output
fn factorial(n: Int): Int is deterministic =
if n <= 1 then 1
else n * factorial(n - 1)
fn multiply(a: Int, b: Int): Int is commutative = a * b
// A commutative function - order of arguments doesn't matter
fn multiply(a: Int, b: Int): Int is commutative =
a * b
fn abs(x: Int): Int is idempotent = if x < 0 then 0 - x else x
// An idempotent function - absolute value
fn abs(x: Int): Int is idempotent =
if x < 0 then 0 - x else x
// Test the functions
let sumResult = add(5, 3)
let factResult = factorial(5)
let productResult = multiply(7, 6)
let absResult = abs(0 - 5)
// Print results
fn printResults(): Unit with {Console} = {
Console.print("add(5, 3) = " + toString(sumResult))
Console.print("factorial(5) = " + toString(factResult))

View File

@@ -1,82 +1,42 @@
// Behavioral Types Demo
// Demonstrates compile-time verification of function properties
// ============================================================
// PART 1: Pure Functions
// ============================================================
// Pure functions have no side effects
fn add(a: Int, b: Int): Int is pure = a + b
fn subtract(a: Int, b: Int): Int is pure = a - b
// ============================================================
// PART 2: Commutative Functions
// ============================================================
// Commutative functions: f(a, b) = f(b, a)
fn multiply(a: Int, b: Int): Int is commutative = a * b
fn sum(a: Int, b: Int): Int is commutative = a + b
// ============================================================
// PART 3: Idempotent Functions
// ============================================================
// Idempotent functions: f(f(x)) = f(x)
fn abs(x: Int): Int is idempotent =
if x < 0 then 0 - x else x
fn abs(x: Int): Int is idempotent = if x < 0 then 0 - x else x
fn identity(x: Int): Int is idempotent = x
// ============================================================
// PART 4: Deterministic Functions
// ============================================================
fn factorial(n: Int): Int is deterministic = if n <= 1 then 1 else n * factorial(n - 1)
// Deterministic functions always produce the same output for the same input
fn factorial(n: Int): Int is deterministic =
if n <= 1 then 1 else n * factorial(n - 1)
fn fib(n: Int): Int is deterministic = if n <= 1 then n else fib(n - 1) + fib(n - 2)
fn fib(n: Int): Int is deterministic =
if n <= 1 then n else fib(n - 1) + fib(n - 2)
fn sumTo(n: Int): Int is total = if n <= 0 then 0 else n + sumTo(n - 1)
// ============================================================
// PART 5: Total Functions
// ============================================================
// Total functions are defined for all inputs (no infinite loops, no exceptions)
fn sumTo(n: Int): Int is total =
if n <= 0 then 0 else n + sumTo(n - 1)
fn power(base: Int, exp: Int): Int is total =
if exp <= 0 then 1 else base * power(base, exp - 1)
// ============================================================
// RESULTS
// ============================================================
fn power(base: Int, exp: Int): Int is total = if exp <= 0 then 1 else base * power(base, exp - 1)
fn main(): Unit with {Console} = {
Console.print("=== Behavioral Types Demo ===")
Console.print("")
Console.print("Part 1: Pure functions")
Console.print(" add(5, 3) = " + toString(add(5, 3)))
Console.print(" subtract(10, 4) = " + toString(subtract(10, 4)))
Console.print("")
Console.print("Part 2: Commutative functions")
Console.print(" multiply(7, 6) = " + toString(multiply(7, 6)))
Console.print(" sum(10, 20) = " + toString(sum(10, 20)))
Console.print("")
Console.print("Part 3: Idempotent functions")
Console.print(" abs(-42) = " + toString(abs(0 - 42)))
Console.print(" identity(100) = " + toString(identity(100)))
Console.print("")
Console.print("Part 4: Deterministic functions")
Console.print(" factorial(5) = " + toString(factorial(5)))
Console.print(" fib(10) = " + toString(fib(10)))
Console.print("")
Console.print("Part 5: Total functions")
Console.print(" sumTo(10) = " + toString(sumTo(10)))
Console.print(" power(2, 8) = " + toString(power(2, 8)))

View File

@@ -1,31 +1,7 @@
// Demonstrating built-in effects in Lux
//
// Lux provides several built-in effects:
// - Console: print and read from terminal
// - Fail: early termination with error
// - State: get/put mutable state (requires runtime initialization)
// - Reader: read-only environment access (requires runtime initialization)
//
// This example demonstrates Console and Fail effects.
//
// Expected output:
// Starting computation...
// Step 1: validating input
// Step 2: processing
// Result: 42
// Done!
fn safeDivide(a: Int, b: Int): Int with {Fail} = if b == 0 then Fail.fail("Division by zero") else a / b
// A function that can fail
fn safeDivide(a: Int, b: Int): Int with {Fail} =
if b == 0 then Fail.fail("Division by zero")
else a / b
fn validatePositive(n: Int): Int with {Fail} = if n < 0 then Fail.fail("Negative number not allowed") else n
// A function that validates input
fn validatePositive(n: Int): Int with {Fail} =
if n < 0 then Fail.fail("Negative number not allowed")
else n
// A computation that uses multiple effects
fn compute(input: Int): Int with {Console, Fail} = {
Console.print("Starting computation...")
Console.print("Step 1: validating input")
@@ -36,7 +12,6 @@ fn compute(input: Int): Int with {Console, Fail} = {
result
}
// Main function
fn main(): Unit with {Console} = {
let result = run compute(21) with {}
Console.print("Done!")

View File

@@ -1,14 +1,3 @@
// Counter Example - A simple interactive counter using TEA pattern
//
// This example demonstrates:
// - Model-View-Update architecture (TEA)
// - Html DSL for describing UI (inline version)
// - Message-based state updates
// ============================================================================
// Html Types (subset of stdlib/html)
// ============================================================================
type Html<M> =
| Element(String, List<Attr<M>>, List<Html<M>>)
| Text(String)
@@ -19,86 +8,56 @@ type Attr<M> =
| Id(String)
| OnClick(M)
// Html builder helpers
fn div<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
Element("div", attrs, children)
fn div<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("div", attrs, children)
fn span<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
Element("span", attrs, children)
fn span<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("span", attrs, children)
fn h1<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
Element("h1", attrs, children)
fn h1<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("h1", attrs, children)
fn button<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> =
Element("button", attrs, children)
fn button<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("button", attrs, children)
fn text<M>(content: String): Html<M> =
Text(content)
fn text<M>(content: String): Html<M> = Text(content)
fn class<M>(name: String): Attr<M> =
Class(name)
fn class<M>(name: String): Attr<M> = Class(name)
fn onClick<M>(msg: M): Attr<M> =
OnClick(msg)
// ============================================================================
// Model - The application state (using ADT wrapper)
// ============================================================================
fn onClick<M>(msg: M): Attr<M> = OnClick(msg)
type Model =
| Counter(Int)
fn getCount(model: Model): Int =
match model {
Counter(n) => n
}
Counter(n) => n,
}
fn init(): Model = Counter(0)
// ============================================================================
// Messages - Events that can occur
// ============================================================================
type Msg =
| Increment
| Decrement
| Reset
// ============================================================================
// Update - State transitions
// ============================================================================
fn update(model: Model, msg: Msg): Model =
match msg {
Increment => Counter(getCount(model) + 1),
Decrement => Counter(getCount(model) - 1),
Reset => Counter(0)
}
// ============================================================================
// View - Render the UI
// ============================================================================
Reset => Counter(0),
}
fn viewCounter(count: Int): Html<Msg> = {
let countText = text(toString(count))
let countSpan = span([class("count")], [countText])
let displayDiv = div([class("counter-display")], [countSpan])
let minusBtn = button([onClick(Decrement), class("btn")], [text("-")])
let resetBtn = button([onClick(Reset), class("btn btn-reset")], [text("Reset")])
let plusBtn = button([onClick(Increment), class("btn")], [text("+")])
let buttonsDiv = div([class("counter-buttons")], [minusBtn, resetBtn, plusBtn])
let title = h1([], [text("Counter")])
div([class("counter-app")], [title, displayDiv, buttonsDiv])
}
fn view(model: Model): Html<Msg> = viewCounter(getCount(model))
// ============================================================================
// Debug: Print Html structure
// ============================================================================
fn showAttr(attr: Attr<Msg>): String =
match attr {
Class(s) => "class=\"" + s + "\"",
@@ -106,27 +65,27 @@ fn showAttr(attr: Attr<Msg>): String =
OnClick(msg) => match msg {
Increment => "onclick=\"Increment\"",
Decrement => "onclick=\"Decrement\"",
Reset => "onclick=\"Reset\""
}
}
Reset => "onclick=\"Reset\"",
},
}
fn showAttrs(attrs: List<Attr<Msg>>): String =
match List.head(attrs) {
None => "",
Some(a) => match List.tail(attrs) {
None => showAttr(a),
Some(rest) => showAttr(a) + " " + showAttrs(rest)
}
}
Some(rest) => showAttr(a) + " " + showAttrs(rest),
},
}
fn showChildren(children: List<Html<Msg>>, indent: Int): String =
match List.head(children) {
None => "",
Some(c) => match List.tail(children) {
None => showHtml(c, indent),
Some(rest) => showHtml(c, indent) + showChildren(rest, indent)
}
}
Some(rest) => showHtml(c, indent) + showChildren(rest, indent),
},
}
fn showHtml(html: Html<Msg>, indent: Int): String =
match html {
@@ -137,12 +96,8 @@ fn showHtml(html: Html<Msg>, indent: Int): String =
let attrPart = if String.length(attrStr) > 0 then " " + attrStr else ""
let childStr = showChildren(children, indent + 2)
"<" + tag + attrPart + ">" + childStr + "</" + tag + ">"
}
}
// ============================================================================
// Entry point
// ============================================================================
},
}
fn main(): Unit with {Console} = {
let model = init()
@@ -150,24 +105,19 @@ fn main(): Unit with {Console} = {
Console.print("")
Console.print("Initial count: " + toString(getCount(model)))
Console.print("")
let m1 = update(model, Increment)
Console.print("After Increment: " + toString(getCount(m1)))
let m2 = update(m1, Increment)
Console.print("After Increment: " + toString(getCount(m2)))
let m3 = update(m2, Increment)
Console.print("After Increment: " + toString(getCount(m3)))
let m4 = update(m3, Decrement)
Console.print("After Decrement: " + toString(getCount(m4)))
let m5 = update(m4, Reset)
Console.print("After Reset: " + toString(getCount(m5)))
Console.print("")
Console.print("=== View (HTML Structure) ===")
Console.print(showHtml(view(m2), 0))
}
let output = run main() with {}

View File

@@ -1,57 +1,37 @@
// Demonstrating algebraic data types and pattern matching
//
// Expected output:
// Tree sum: 8
// Tree depth: 3
// Safe divide 10/2: Result: 5
// Safe divide 10/0: Division by zero!
// Define a binary tree
type Tree =
| Leaf(Int)
| Node(Tree, Tree)
// Sum all values in a tree
fn sumTree(tree: Tree): Int =
match tree {
Leaf(n) => n,
Node(left, right) => sumTree(left) + sumTree(right)
}
Node(left, right) => sumTree(left) + sumTree(right),
}
// Find the depth of a tree
fn depth(tree: Tree): Int =
match tree {
Leaf(_) => 1,
Node(left, right) => {
let leftDepth = depth(left)
let rightDepth = depth(right)
1 + (if leftDepth > rightDepth then leftDepth else rightDepth)
}
}
// Example tree:
// Node
// / \
// Node Leaf(5)
// / \
// Leaf(1) Leaf(2)
1 + if leftDepth > rightDepth then leftDepth else rightDepth
},
}
let myTree = Node(Node(Leaf(1), Leaf(2)), Leaf(5))
let treeSum = sumTree(myTree)
let treeDepth = depth(myTree)
// Option type example
fn safeDivide(a: Int, b: Int): Option<Int> =
if b == 0 then None
else Some(a / b)
fn safeDivide(a: Int, b: Int): Option<Int> = if b == 0 then None else Some(a / b)
fn showResult(result: Option<Int>): String =
match result {
None => "Division by zero!",
Some(n) => "Result: " + toString(n)
}
Some(n) => "Result: " + toString(n),
}
// Print results
fn printResults(): Unit with {Console} = {
Console.print("Tree sum: " + toString(treeSum))
Console.print("Tree depth: " + toString(treeDepth))

View File

@@ -1,17 +1,8 @@
// Demonstrating algebraic effects in Lux
//
// Expected output:
// [info] Processing data...
// [debug] Result computed
// Final result: 42
// Define a custom logging effect
effect Logger {
fn log(level: String, msg: String): Unit
fn getLevel(): String
}
// A function that uses the Logger effect
fn processData(data: Int): Int with {Logger} = {
Logger.log("info", "Processing data...")
let result = data * 2
@@ -19,17 +10,15 @@ fn processData(data: Int): Int with {Logger} = {
result
}
// A handler that prints logs to console
handler consoleLogger: Logger {
fn log(level, msg) = Console.print("[" + level + "] " + msg)
fn getLevel() = "debug"
}
// Run and print
fn main(): Unit with {Console} = {
let result = run processData(21) with {
Logger = consoleLogger
}
Logger = consoleLogger,
}
Console.print("Final result: " + toString(result))
}

View File

@@ -1,16 +1,7 @@
// Factorial function demonstrating recursion
//
// Expected output: 10! = 3628800
fn factorial(n: Int): Int = if n <= 1 then 1 else n * factorial(n - 1)
fn factorial(n: Int): Int =
if n <= 1 then 1
else n * factorial(n - 1)
// Calculate factorial of 10
let result = factorial(10)
// Print result using Console effect
fn showResult(): Unit with {Console} =
Console.print("10! = " + toString(result))
fn showResult(): Unit with {Console} = Console.print("10! = " + toString(result))
let output = run showResult() with {}

View File

@@ -1,9 +1,6 @@
// File I/O example - demonstrates the File effect
//
// This script reads a file, counts lines/words, and writes a report
fn countLines(content: String): Int = {
let lines = String.split(content, "\n")
let lines = String.split(content, "
")
List.length(lines)
}
@@ -14,35 +11,28 @@ fn countWords(content: String): Int = {
fn analyzeFile(path: String): Unit with {File, Console} = {
Console.print("Analyzing file: " + path)
if File.exists(path) then {
let content = File.read(path)
let lines = countLines(content)
let words = countWords(content)
let chars = String.length(content)
Console.print(" Lines: " + toString(lines))
Console.print(" Words: " + toString(words))
Console.print(" Chars: " + toString(chars))
} else {
} else {
Console.print(" Error: File not found!")
}
}
}
fn main(): Unit with {File, Console} = {
Console.print("=== Lux File Analyzer ===")
Console.print("")
// Analyze this file itself
analyzeFile("examples/file_io.lux")
Console.print("")
// Analyze hello.lux
analyzeFile("examples/hello.lux")
Console.print("")
// Write a report
let report = "File analysis complete.\nAnalyzed 2 files."
let report = "File analysis complete.
Analyzed 2 files."
File.write("/tmp/lux_report.txt", report)
Console.print("Report written to /tmp/lux_report.txt")
}

View File

@@ -1,55 +1,39 @@
// Demonstrating functional programming features
//
// Expected output:
// apply(double, 21) = 42
// compose(addOne, double)(5) = 11
// pipe: 5 |> double |> addOne |> square = 121
// curried add5(10) = 15
// partial times3(7) = 21
// record transform = 30
// Higher-order functions
fn apply(f: fn(Int): Int, x: Int): Int = f(x)
fn compose(f: fn(Int): Int, g: fn(Int): Int): fn(Int): Int =
fn(x: Int): Int => f(g(x))
fn compose(f: fn(Int): Int, g: fn(Int): Int): fn(Int): Int = fn(x: Int): Int => f(g(x))
// Basic functions
fn double(x: Int): Int = x * 2
fn addOne(x: Int): Int = x + 1
fn square(x: Int): Int = x * x
// Using apply
let result1 = apply(double, 21)
// Using compose
let doubleAndAddOne = compose(addOne, double)
let result2 = doubleAndAddOne(5)
// Using the pipe operator
let result3 = 5 |> double |> addOne |> square
let result3 = square(addOne(double(5)))
// Currying example
fn add(a: Int): fn(Int): Int =
fn(b: Int): Int => a + b
fn add(a: Int): fn(Int): Int = fn(b: Int): Int => a + b
let add5 = add(5)
let result4 = add5(10)
// Partial application simulation
fn multiply(a: Int, b: Int): Int = a * b
let times3 = fn(x: Int): Int => multiply(3, x)
let result5 = times3(7)
// Working with records
let transform = fn(record: { x: Int, y: Int }): Int =>
record.x + record.y
let transform = fn(record: { x: Int, y: Int }): Int => record.x + record.y
let point = { x: 10, y: 20 }
let recordSum = transform(point)
// Print all results
fn printResults(): Unit with {Console} = {
Console.print("apply(double, 21) = " + toString(result1))
Console.print("compose(addOne, double)(5) = " + toString(result2))

View File

@@ -1,45 +1,34 @@
// Demonstrating generic type parameters in Lux
//
// Expected output:
// identity(42) = 42
// identity("hello") = hello
// first(MkPair(1, "one")) = 1
// second(MkPair(1, "one")) = one
// map(Some(21), double) = Some(42)
// Generic identity function
fn identity<T>(x: T): T = x
// Generic pair type
type Pair<A, B> =
| MkPair(A, B)
fn first<A, B>(p: Pair<A, B>): A =
match p {
MkPair(a, _) => a
}
MkPair(a, _) => a,
}
fn second<A, B>(p: Pair<A, B>): B =
match p {
MkPair(_, b) => b
}
MkPair(_, b) => b,
}
// Generic map function for Option
fn mapOption<T, U>(opt: Option<T>, f: fn(T): U): Option<U> =
match opt {
None => None,
Some(x) => Some(f(x))
}
Some(x) => Some(f(x)),
}
// Helper function for testing
fn double(x: Int): Int = x * 2
// Test usage
let id_int = identity(42)
let id_str = identity("hello")
let pair = MkPair(1, "one")
let fst = first(pair)
let snd = second(pair)
let doubled = mapOption(Some(21), double)
@@ -47,8 +36,8 @@ let doubled = mapOption(Some(21), double)
fn showOption(opt: Option<Int>): String =
match opt {
None => "None",
Some(x) => "Some(" + toString(x) + ")"
}
Some(x) => "Some(" + toString(x) + ")",
}
fn printResults(): Unit with {Console} = {
Console.print("identity(42) = " + toString(id_int))

View File

@@ -1,21 +1,8 @@
// Demonstrating resumable effect handlers in Lux
//
// Handlers can use `resume(value)` to return a value to the effect call site
// and continue the computation. This enables powerful control flow patterns.
//
// Expected output:
// [INFO] Starting computation
// [DEBUG] Intermediate result: 10
// [INFO] Computation complete
// Final result: 20
// Define a custom logging effect
effect Logger {
fn log(level: String, msg: String): Unit
fn getLogLevel(): String
}
// A function that uses the Logger effect
fn compute(): Int with {Logger} = {
Logger.log("INFO", "Starting computation")
let x = 10
@@ -25,20 +12,19 @@ fn compute(): Int with {Logger} = {
result
}
// A handler that prints logs with brackets and resumes with Unit
handler prettyLogger: Logger {
fn log(level, msg) = {
fn log(level, msg) =
{
Console.print("[" + level + "] " + msg)
resume(())
}
}
fn getLogLevel() = resume("DEBUG")
}
// Main function
fn main(): Unit with {Console} = {
let result = run compute() with {
Logger = prettyLogger
}
Logger = prettyLogger,
}
Console.print("Final result: " + toString(result))
}

View File

@@ -1,10 +1,3 @@
// Hello World in Lux
// Demonstrates basic effect usage
//
// Expected output: Hello, World!
fn greet(): Unit with {Console} = Console.print("Hello, World!")
fn greet(): Unit with {Console} =
Console.print("Hello, World!")
// Run the greeting with the Console effect
let output = run greet() with {}

View File

@@ -1,91 +1,72 @@
// HTTP example - demonstrates the Http effect
//
// This script makes HTTP requests and parses JSON responses
fn main(): Unit with {Console, Http} = {
Console.print("=== Lux HTTP Example ===")
Console.print("")
// Make a GET request to a public API
Console.print("Fetching data from httpbin.org...")
Console.print("")
match Http.get("https://httpbin.org/get") {
Ok(response) => {
Console.print("GET request successful!")
Console.print(" Status: " + toString(response.status))
Console.print(" Body length: " + toString(String.length(response.body)) + " bytes")
Console.print("")
// Parse the JSON response
match Json.parse(response.body) {
Ok(json) => {
Console.print("Parsed JSON response:")
match Json.get(json, "origin") {
Some(origin) => match Json.asString(origin) {
Some(ip) => Console.print(" Your IP: " + ip),
None => Console.print(" origin: (not a string)")
},
None => Console.print(" origin: (not found)")
}
None => Console.print(" origin: (not a string)"),
},
None => Console.print(" origin: (not found)"),
}
match Json.get(json, "url") {
Some(url) => match Json.asString(url) {
Some(u) => Console.print(" URL: " + u),
None => Console.print(" url: (not a string)")
},
None => Console.print(" url: (not found)")
}
},
Err(e) => Console.print("JSON parse error: " + e)
}
},
Err(e) => Console.print("GET request failed: " + e)
}
None => Console.print(" url: (not a string)"),
},
None => Console.print(" url: (not found)"),
}
},
Err(e) => Console.print("JSON parse error: " + e),
}
},
Err(e) => Console.print("GET request failed: " + e),
}
Console.print("")
Console.print("--- POST Request ---")
Console.print("")
// Make a POST request with JSON body
let requestBody = Json.object([("message", Json.string("Hello from Lux!")), ("version", Json.int(1))])
Console.print("Sending POST with JSON body...")
Console.print(" Body: " + Json.stringify(requestBody))
Console.print("")
match Http.postJson("https://httpbin.org/post", requestBody) {
Ok(response) => {
Console.print("POST request successful!")
Console.print(" Status: " + toString(response.status))
// Parse and extract what we sent
match Json.parse(response.body) {
Ok(json) => match Json.get(json, "json") {
Some(sentJson) => {
Console.print(" Server received:")
Console.print(" " + Json.stringify(sentJson))
},
None => Console.print(" (no json field in response)")
},
Err(e) => Console.print("JSON parse error: " + e)
}
},
Err(e) => Console.print("POST request failed: " + e)
}
},
None => Console.print(" (no json field in response)"),
},
Err(e) => Console.print("JSON parse error: " + e),
}
},
Err(e) => Console.print("POST request failed: " + e),
}
Console.print("")
Console.print("--- Headers ---")
Console.print("")
// Show response headers
match Http.get("https://httpbin.org/headers") {
Ok(response) => {
Console.print("Response headers (first 5):")
let count = 0
// Note: Can't easily iterate with effects in callbacks, so just show count
Console.print(" Total headers: " + toString(List.length(response.headers)))
},
Err(e) => Console.print("Request failed: " + e)
}
},
Err(e) => Console.print("Request failed: " + e),
}
}
let result = run main() with {}

View File

@@ -1,68 +1,31 @@
// HTTP API Example
//
// A complete REST API demonstrating:
// - Route matching with path parameters
// - Response builders
// - JSON construction
//
// Run with: lux examples/http_api.lux
// Test with:
// curl http://localhost:8080/
// curl http://localhost:8080/users
// curl http://localhost:8080/users/42
fn httpOk(body: String): { status: Int, body: String } = { status: 200, body: body }
// ============================================================
// Response Helpers
// ============================================================
fn httpCreated(body: String): { status: Int, body: String } = { status: 201, body: body }
fn httpOk(body: String): { status: Int, body: String } =
{ status: 200, body: body }
fn httpNotFound(body: String): { status: Int, body: String } = { status: 404, body: body }
fn httpCreated(body: String): { status: Int, body: String } =
{ status: 201, body: body }
fn httpBadRequest(body: String): { status: Int, body: String } = { status: 400, body: body }
fn httpNotFound(body: String): { status: Int, body: String } =
{ status: 404, body: body }
fn jsonEscape(s: String): String = String.replace(String.replace(s, "\\", "\\\\"), "\"", "\\\"")
fn httpBadRequest(body: String): { status: Int, body: String } =
{ status: 400, body: body }
fn jsonStr(key: String, value: String): String = "\"" + jsonEscape(key) + "\":\"" + jsonEscape(value) + "\""
// ============================================================
// JSON Helpers
// ============================================================
fn jsonNum(key: String, value: Int): String = "\"" + jsonEscape(key) + "\":" + toString(value)
fn jsonEscape(s: String): String =
String.replace(String.replace(s, "\\", "\\\\"), "\"", "\\\"")
fn jsonObj(content: String): String = toString(" + content + ")
fn jsonStr(key: String, value: String): String =
"\"" + jsonEscape(key) + "\":\"" + jsonEscape(value) + "\""
fn jsonArr(content: String): String = "[" + content + "]"
fn jsonNum(key: String, value: Int): String =
"\"" + jsonEscape(key) + "\":" + toString(value)
fn jsonObj(content: String): String =
"{" + content + "}"
fn jsonArr(content: String): String =
"[" + content + "]"
fn jsonError(message: String): String =
jsonObj(jsonStr("error", message))
// ============================================================
// Path Matching
// ============================================================
fn jsonError(message: String): String = jsonObj(jsonStr("error", message))
fn pathMatches(path: String, pattern: String): Bool = {
let pathParts = String.split(path, "/")
let patternParts = String.split(pattern, "/")
if List.length(pathParts) != List.length(patternParts) then false
else matchParts(pathParts, patternParts)
if List.length(pathParts) != List.length(patternParts) then false else matchParts(pathParts, patternParts)
}
fn matchParts(pathParts: List<String>, patternParts: List<String>): Bool = {
if List.length(pathParts) == 0 then true
else {
if List.length(pathParts) == 0 then true else {
match List.head(pathParts) {
None => true,
Some(pathPart) => {
@@ -74,12 +37,12 @@ fn matchParts(pathParts: List<String>, patternParts: List<String>): Bool = {
let restPath = Option.getOrElse(List.tail(pathParts), [])
let restPattern = Option.getOrElse(List.tail(patternParts), [])
matchParts(restPath, restPattern)
} else false
}
}
}
}
}
} else false
},
}
},
}
}
}
fn getPathSegment(path: String, index: Int): Option<String> = {
@@ -87,15 +50,9 @@ fn getPathSegment(path: String, index: Int): Option<String> = {
List.get(parts, index + 1)
}
// ============================================================
// Handlers
// ============================================================
fn indexHandler(): { status: Int, body: String } = httpOk(jsonObj(jsonStr("message", "Welcome to Lux HTTP API")))
fn indexHandler(): { status: Int, body: String } =
httpOk(jsonObj(jsonStr("message", "Welcome to Lux HTTP API")))
fn healthHandler(): { status: Int, body: String } =
httpOk(jsonObj(jsonStr("status", "healthy")))
fn healthHandler(): { status: Int, body: String } = httpOk(jsonObj(jsonStr("status", "healthy")))
fn listUsersHandler(): { status: Int, body: String } = {
let user1 = jsonObj(jsonNum("id", 1) + "," + jsonStr("name", "Alice"))
@@ -108,9 +65,9 @@ fn getUserHandler(path: String): { status: Int, body: String } = {
Some(id) => {
let body = jsonObj(jsonStr("id", id) + "," + jsonStr("name", "User " + id))
httpOk(body)
},
None => httpNotFound(jsonError("User not found"))
}
},
None => httpNotFound(jsonError("User not found")),
}
}
fn createUserHandler(body: String): { status: Int, body: String } = {
@@ -118,34 +75,21 @@ fn createUserHandler(body: String): { status: Int, body: String } = {
httpCreated(newUser)
}
// ============================================================
// Router
// ============================================================
fn router(method: String, path: String, body: String): { status: Int, body: String } = {
if method == "GET" && path == "/" then indexHandler()
else if method == "GET" && path == "/health" then healthHandler()
else if method == "GET" && path == "/users" then listUsersHandler()
else if method == "GET" && pathMatches(path, "/users/:id") then getUserHandler(path)
else if method == "POST" && path == "/users" then createUserHandler(body)
else httpNotFound(jsonError("Not found: " + path))
if method == "GET" && path == "/" then indexHandler() else if method == "GET" && path == "/health" then healthHandler() else if method == "GET" && path == "/users" then listUsersHandler() else if method == "GET" && pathMatches(path, "/users/:id") then getUserHandler(path) else if method == "POST" && path == "/users" then createUserHandler(body) else httpNotFound(jsonError("Not found: " + path))
}
// ============================================================
// Server
// ============================================================
fn serveLoop(remaining: Int): Unit with {Console, HttpServer} = {
if remaining <= 0 then {
Console.print("Max requests reached, stopping server.")
HttpServer.stop()
} else {
} else {
let req = HttpServer.accept()
Console.print(req.method + " " + req.path)
let resp = router(req.method, req.path, req.body)
HttpServer.respond(resp.status, resp.body)
serveLoop(remaining - 1)
}
}
}
fn main(): Unit with {Console, HttpServer} = {

View File

@@ -1,24 +1,4 @@
// HTTP Router Example
//
// Demonstrates the HTTP helper library with:
// - Path pattern matching
// - Response builders
// - JSON helpers
//
// Run with: lux examples/http_router.lux
// Test with:
// curl http://localhost:8080/
// curl http://localhost:8080/users
// curl http://localhost:8080/users/42
import stdlib/http
// ============================================================
// Route Handlers
// ============================================================
fn indexHandler(): { status: Int, body: String } =
httpOk("Welcome to Lux HTTP Framework!")
fn indexHandler(): { status: Int, body: String } = httpOk("Welcome to Lux HTTP Framework!")
fn listUsersHandler(): { status: Int, body: String } = {
let user1 = jsonObject(jsonJoin([jsonNumber("id", 1), jsonString("name", "Alice")]))
@@ -32,41 +12,28 @@ fn getUserHandler(path: String): { status: Int, body: String } = {
Some(id) => {
let body = jsonObject(jsonJoin([jsonString("id", id), jsonString("name", "User " + id)]))
httpOk(body)
},
None => httpNotFound(jsonErrorMsg("User ID required"))
}
},
None => httpNotFound(jsonErrorMsg("User ID required")),
}
}
fn healthHandler(): { status: Int, body: String } =
httpOk(jsonObject(jsonString("status", "healthy")))
// ============================================================
// Router
// ============================================================
fn healthHandler(): { status: Int, body: String } = httpOk(jsonObject(jsonString("status", "healthy")))
fn router(method: String, path: String, body: String): { status: Int, body: String } = {
if method == "GET" && path == "/" then indexHandler()
else if method == "GET" && path == "/health" then healthHandler()
else if method == "GET" && path == "/users" then listUsersHandler()
else if method == "GET" && pathMatches(path, "/users/:id") then getUserHandler(path)
else httpNotFound(jsonErrorMsg("Not found: " + path))
if method == "GET" && path == "/" then indexHandler() else if method == "GET" && path == "/health" then healthHandler() else if method == "GET" && path == "/users" then listUsersHandler() else if method == "GET" && pathMatches(path, "/users/:id") then getUserHandler(path) else httpNotFound(jsonErrorMsg("Not found: " + path))
}
// ============================================================
// Server
// ============================================================
fn serveLoop(remaining: Int): Unit with {Console, HttpServer} = {
if remaining <= 0 then {
Console.print("Max requests reached, stopping server.")
HttpServer.stop()
} else {
} else {
let req = HttpServer.accept()
Console.print(req.method + " " + req.path)
let resp = router(req.method, req.path, req.body)
HttpServer.respond(resp.status, resp.body)
serveLoop(remaining - 1)
}
}
}
fn main(): Unit with {Console, HttpServer} = {

View File

@@ -1,13 +1,6 @@
// Test file for JIT compilation
// This uses only features the JIT supports: integers, arithmetic, conditionals, functions
fn fib(n: Int): Int = if n <= 1 then n else fib(n - 1) + fib(n - 2)
fn fib(n: Int): Int =
if n <= 1 then n
else fib(n - 1) + fib(n - 2)
fn factorial(n: Int): Int =
if n <= 1 then 1
else n * factorial(n - 1)
fn factorial(n: Int): Int = if n <= 1 then 1 else n * factorial(n - 1)
fn main(): Unit with {Console} = {
let fibResult = fib(30)

View File

@@ -1,107 +1,79 @@
// JSON example - demonstrates JSON parsing and manipulation
//
// This script parses JSON, extracts values, and builds new JSON structures
fn main(): Unit with {Console, File} = {
Console.print("=== Lux JSON Example ===")
Console.print("")
// First, build some JSON programmatically
Console.print("=== Building JSON ===")
Console.print("")
let name = Json.string("Alice")
let age = Json.int(30)
let active = Json.bool(true)
let scores = Json.array([Json.int(95), Json.int(87), Json.int(92)])
let person = Json.object([("name", name), ("age", age), ("active", active), ("scores", scores)])
Console.print("Built JSON:")
let pretty = Json.prettyPrint(person)
Console.print(pretty)
Console.print("")
// Stringify to a compact string
let jsonStr = Json.stringify(person)
Console.print("Compact: " + jsonStr)
Console.print("")
// Write to file and read back to test parsing
File.write("/tmp/test.json", jsonStr)
Console.print("Written to /tmp/test.json")
Console.print("")
// Read and parse from file
Console.print("=== Parsing JSON ===")
Console.print("")
let content = File.read("/tmp/test.json")
Console.print("Read from file: " + content)
Console.print("")
match Json.parse(content) {
Ok(json) => {
Console.print("Parse succeeded!")
Console.print("")
// Get string field
Console.print("Extracting fields:")
match Json.get(json, "name") {
Some(nameJson) => match Json.asString(nameJson) {
Some(n) => Console.print(" name: " + n),
None => Console.print(" name: (not a string)")
},
None => Console.print(" name: (not found)")
}
// Get int field
None => Console.print(" name: (not a string)"),
},
None => Console.print(" name: (not found)"),
}
match Json.get(json, "age") {
Some(ageJson) => match Json.asInt(ageJson) {
Some(a) => Console.print(" age: " + toString(a)),
None => Console.print(" age: (not an int)")
},
None => Console.print(" age: (not found)")
}
// Get bool field
None => Console.print(" age: (not an int)"),
},
None => Console.print(" age: (not found)"),
}
match Json.get(json, "active") {
Some(activeJson) => match Json.asBool(activeJson) {
Some(a) => Console.print(" active: " + toString(a)),
None => Console.print(" active: (not a bool)")
},
None => Console.print(" active: (not found)")
}
// Get array field
None => Console.print(" active: (not a bool)"),
},
None => Console.print(" active: (not found)"),
}
match Json.get(json, "scores") {
Some(scoresJson) => match Json.asArray(scoresJson) {
Some(arr) => {
Console.print(" scores: " + toString(List.length(arr)) + " items")
// Get first score
match Json.getIndex(scoresJson, 0) {
Some(firstJson) => match Json.asInt(firstJson) {
Some(first) => Console.print(" first score: " + toString(first)),
None => Console.print(" first score: (not an int)")
},
None => Console.print(" (no first element)")
}
},
None => Console.print(" scores: (not an array)")
},
None => Console.print(" scores: (not found)")
}
None => Console.print(" first score: (not an int)"),
},
None => Console.print(" (no first element)"),
}
},
None => Console.print(" scores: (not an array)"),
},
None => Console.print(" scores: (not found)"),
}
Console.print("")
// Get the keys
Console.print("Object keys:")
match Json.keys(json) {
Some(ks) => Console.print(" " + String.join(ks, ", ")),
None => Console.print(" (not an object)")
}
},
Err(e) => Console.print("Parse error: " + e)
}
None => Console.print(" (not an object)"),
}
},
Err(e) => Console.print("Parse error: " + e),
}
Console.print("")
Console.print("=== JSON Null Check ===")
let nullVal = Json.null()

View File

@@ -1,17 +1,9 @@
// Main program that imports modules
import examples/modules/math_utils
import examples/modules/string_utils
fn main(): Unit with {Console} = {
Console.print("=== Testing Module Imports ===")
// Use math_utils
Console.print("square(5) = " + toString(math_utils.square(5)))
Console.print("cube(3) = " + toString(math_utils.cube(3)))
Console.print("factorial(6) = " + toString(math_utils.factorial(6)))
Console.print("sumRange(1, 10) = " + toString(math_utils.sumRange(1, 10)))
// Use string_utils
Console.print(string_utils.greet("World"))
Console.print(string_utils.exclaim("Modules work"))
Console.print("repeat(\"ab\", 3) = " + string_utils.repeat("ab", 3))

View File

@@ -1,15 +1,7 @@
// Test selective imports
import examples/modules/math_utils.{square, factorial}
import examples/modules/string_utils as str
fn main(): Unit with {Console} = {
Console.print("=== Selective & Aliased Imports ===")
// Direct imports (no module prefix)
Console.print("square(7) = " + toString(square(7)))
Console.print("factorial(5) = " + toString(factorial(5)))
// Aliased import
Console.print(str.greet("Lux"))
Console.print(str.exclaim("Aliased imports work"))
}

View File

@@ -1,10 +1,5 @@
// Test wildcard imports
import examples/modules/math_utils.*
fn main(): Unit with {Console} = {
Console.print("=== Wildcard Imports ===")
// All functions available directly
Console.print("square(4) = " + toString(square(4)))
Console.print("cube(4) = " + toString(cube(4)))
Console.print("factorial(4) = " + toString(factorial(4)))

View File

@@ -1,14 +1,7 @@
// Math utilities module
// Exports: square, cube, factorial
fn square(n: Int): Int = n * n
pub fn square(n: Int): Int = n * n
fn cube(n: Int): Int = n * n * n
pub fn cube(n: Int): Int = n * n * n
fn factorial(n: Int): Int = if n <= 1 then 1 else n * factorial(n - 1)
pub fn factorial(n: Int): Int =
if n <= 1 then 1
else n * factorial(n - 1)
pub fn sumRange(start: Int, end: Int): Int =
if start > end then 0
else start + sumRange(start + 1, end)
fn sumRange(start: Int, end: Int): Int = if start > end then 0 else start + sumRange(start + 1, end)

View File

@@ -1,11 +1,5 @@
// String utilities module
// Exports: repeat, exclaim
fn repeat(s: String, n: Int): String = if n <= 0 then "" else s + repeat(s, n - 1)
pub fn repeat(s: String, n: Int): String =
if n <= 0 then ""
else s + repeat(s, n - 1)
fn exclaim(s: String): String = s + "!"
pub fn exclaim(s: String): String = s + "!"
pub fn greet(name: String): String =
"Hello, " + name + "!"
fn greet(name: String): String = "Hello, " + name + "!"

View File

@@ -1,17 +1,9 @@
// Example using the standard library
import std/prelude.*
import std/option as opt
fn main(): Unit with {Console} = {
Console.print("=== Using Standard Library ===")
// Prelude functions
Console.print("identity(42) = " + toString(identity(42)))
Console.print("not(true) = " + toString(not(true)))
Console.print("and(true, false) = " + toString(and(true, false)))
Console.print("or(true, false) = " + toString(or(true, false)))
// Option utilities
let x = opt.some(10)
let y = opt.none()
Console.print("isSome(Some(10)) = " + toString(opt.isSome(x)))

View File

@@ -1,47 +1,31 @@
// Demonstrating the pipe operator and functional data processing
//
// Expected output:
// 5 |> double |> addTen |> square = 400
// Pipeline result2 = 42
// process(1) = 144
// process(2) = 196
// process(3) = 256
// clamped = 0
// composed = 121
// Basic transformations
fn double(x: Int): Int = x * 2
fn addTen(x: Int): Int = x + 10
fn square(x: Int): Int = x * x
fn negate(x: Int): Int = -x
// Using the pipe operator for data transformation
let result1 = 5 |> double |> addTen |> square
let result1 = square(addTen(double(5)))
// Chaining multiple operations
let result2 = 3 |> double |> addTen |> double |> addTen
let result2 = addTen(double(addTen(double(3))))
// More complex pipelines
fn process(n: Int): Int =
n |> double |> addTen |> square
fn process(n: Int): Int = square(addTen(double(n)))
// Multiple values through same pipeline
let a = process(1)
let b = process(2)
let c = process(3)
// Conditional in pipeline
fn clampPositive(x: Int): Int =
if x < 0 then 0 else x
fn clampPositive(x: Int): Int = if x < 0 then 0 else x
let clamped = -5 |> double |> clampPositive
let clamped = clampPositive(double(-5))
// Function composition using pipe
fn increment(x: Int): Int = x + 1
let composed = 5 |> double |> increment |> square
let composed = square(increment(double(5)))
// Print results
fn printResults(): Unit with {Console} = {
Console.print("5 |> double |> addTen |> square = " + toString(result1))
Console.print("Pipeline result2 = " + toString(result2))

View File

@@ -1,36 +1,9 @@
// PostgreSQL Database Example
//
// Demonstrates the Postgres effect for database operations.
//
// Prerequisites:
// - PostgreSQL server running locally
// - Database 'testdb' created
// - User 'testuser' with password 'testpass'
//
// To set up:
// createdb testdb
// psql testdb -c "CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT, email TEXT);"
//
// Run with: lux examples/postgres_demo.lux
fn jsonStr(key: String, value: String): String = "\"" + key + "\":\"" + value + "\""
// ============================================================
// Helper Functions
// ============================================================
fn jsonNum(key: String, value: Int): String = "\"" + key + "\":" + toString(value)
fn jsonStr(key: String, value: String): String =
"\"" + key + "\":\"" + value + "\""
fn jsonObj(content: String): String = toString(" + content + ")
fn jsonNum(key: String, value: Int): String =
"\"" + key + "\":" + toString(value)
fn jsonObj(content: String): String =
"{" + content + "}"
// ============================================================
// Database Operations
// ============================================================
// Insert a user
fn insertUser(connId: Int, name: String, email: String): Int with {Console, Postgres} = {
let sql = "INSERT INTO users (name, email) VALUES ('" + name + "', '" + email + "') RETURNING id"
Console.print("Inserting user: " + name)
@@ -38,35 +11,32 @@ fn insertUser(connId: Int, name: String, email: String): Int with {Console, Post
Some(row) => {
Console.print(" Inserted with ID: " + toString(row.id))
row.id
},
},
None => {
Console.print(" Insert failed")
-1
}
}
},
}
}
// Get all users
fn getUsers(connId: Int): Unit with {Console, Postgres} = {
Console.print("Fetching all users...")
let rows = Postgres.query(connId, "SELECT id, name, email FROM users ORDER BY id")
Console.print(" Found " + toString(List.length(rows)) + " users:")
List.forEach(rows, fn(row: { id: Int, name: String, email: String }): Unit with {Console} => {
List.forEach(rows, fn(row: { id: Int, name: String, email: String }): Unit => {
Console.print(" - " + toString(row.id) + ": " + row.name + " <" + row.email + ">")
})
})
}
// Get user by ID
fn getUserById(connId: Int, id: Int): Unit with {Console, Postgres} = {
let sql = "SELECT id, name, email FROM users WHERE id = " + toString(id)
Console.print("Looking up user " + toString(id) + "...")
match Postgres.queryOne(connId, sql) {
Some(row) => Console.print(" Found: " + row.name + " <" + row.email + ">"),
None => Console.print(" User not found")
}
None => Console.print(" User not found"),
}
}
// Update user email
fn updateUserEmail(connId: Int, id: Int, newEmail: String): Unit with {Console, Postgres} = {
let sql = "UPDATE users SET email = '" + newEmail + "' WHERE id = " + toString(id)
Console.print("Updating user " + toString(id) + " email to " + newEmail)
@@ -74,7 +44,6 @@ fn updateUserEmail(connId: Int, id: Int, newEmail: String): Unit with {Console,
Console.print(" Rows affected: " + toString(affected))
}
// Delete user
fn deleteUser(connId: Int, id: Int): Unit with {Console, Postgres} = {
let sql = "DELETE FROM users WHERE id = " + toString(id)
Console.print("Deleting user " + toString(id))
@@ -82,104 +51,63 @@ fn deleteUser(connId: Int, id: Int): Unit with {Console, Postgres} = {
Console.print(" Rows affected: " + toString(affected))
}
// ============================================================
// Transaction Example
// ============================================================
fn transactionDemo(connId: Int): Unit with {Console, Postgres} = {
Console.print("")
Console.print("=== Transaction Demo ===")
// Start transaction
Console.print("Beginning transaction...")
Postgres.beginTx(connId)
// Make some changes
insertUser(connId, "TxUser1", "tx1@example.com")
insertUser(connId, "TxUser2", "tx2@example.com")
// Show users before commit
Console.print("Users before commit:")
getUsers(connId)
// Commit the transaction
Console.print("Committing transaction...")
Postgres.commit(connId)
Console.print("Transaction committed!")
}
// ============================================================
// Main
// ============================================================
fn main(): Unit with {Console, Postgres} = {
Console.print("========================================")
Console.print(" PostgreSQL Demo")
Console.print("========================================")
Console.print("")
// Connect to database
Console.print("Connecting to PostgreSQL...")
let connStr = "host=localhost user=testuser password=testpass dbname=testdb"
let connId = Postgres.connect(connStr)
Console.print("Connected! Connection ID: " + toString(connId))
Console.print("")
// Create table if not exists
Console.print("Creating users table...")
Postgres.execute(connId, "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL, email TEXT NOT NULL)")
Console.print("")
// Clear table for demo
Console.print("Clearing existing data...")
Postgres.execute(connId, "DELETE FROM users")
Console.print("")
// Insert some users
Console.print("=== Inserting Users ===")
let id1 = insertUser(connId, "Alice", "alice@example.com")
let id2 = insertUser(connId, "Bob", "bob@example.com")
let id3 = insertUser(connId, "Charlie", "charlie@example.com")
Console.print("")
// Query all users
Console.print("=== All Users ===")
getUsers(connId)
Console.print("")
// Query single user
Console.print("=== Single User Lookup ===")
getUserById(connId, id2)
Console.print("")
// Update user
Console.print("=== Update User ===")
updateUserEmail(connId, id2, "bob.new@example.com")
getUserById(connId, id2)
Console.print("")
// Delete user
Console.print("=== Delete User ===")
deleteUser(connId, id3)
getUsers(connId)
Console.print("")
// Transaction demo
transactionDemo(connId)
Console.print("")
// Final state
Console.print("=== Final State ===")
getUsers(connId)
Console.print("")
// Close connection
Console.print("Closing connection...")
Postgres.close(connId)
Console.print("Done!")
}
// Note: This will fail if PostgreSQL is not running
// To test the syntax only, you can comment out the last line
let output = run main() with {}

View File

@@ -1,18 +1,6 @@
// Property-Based Testing Example
//
// This example demonstrates property-based testing in Lux,
// where we verify properties hold for randomly generated inputs.
//
// Run with: lux examples/property_testing.lux
// ============================================================
// Generator Functions (using Random effect)
// ============================================================
let CHARS = "abcdefghijklmnopqrstuvwxyz"
fn genInt(min: Int, max: Int): Int with {Random} =
Random.int(min, max)
fn genInt(min: Int, max: Int): Int with {Random} = Random.int(min, max)
fn genIntList(min: Int, max: Int, maxLen: Int): List<Int> with {Random} = {
let len = Random.int(0, maxLen)
@@ -20,10 +8,7 @@ fn genIntList(min: Int, max: Int, maxLen: Int): List<Int> with {Random} = {
}
fn genIntListHelper(min: Int, max: Int, len: Int): List<Int> with {Random} = {
if len <= 0 then
[]
else
List.concat([Random.int(min, max)], genIntListHelper(min, max, len - 1))
if len <= 0 then [] else List.concat([Random.int(min, max)], genIntListHelper(min, max, len - 1))
}
fn genChar(): String with {Random} = {
@@ -37,195 +22,147 @@ fn genString(maxLen: Int): String with {Random} = {
}
fn genStringHelper(len: Int): String with {Random} = {
if len <= 0 then
""
else
genChar() + genStringHelper(len - 1)
if len <= 0 then "" else genChar() + genStringHelper(len - 1)
}
// ============================================================
// Test Runner State
// ============================================================
fn printResult(name: String, passed: Bool, count: Int): Unit with {Console} = {
if passed then
Console.print(" PASS " + name + " (" + toString(count) + " tests)")
else
Console.print(" FAIL " + name)
if passed then Console.print(" PASS " + name + " (" + toString(count) + " tests)") else Console.print(" FAIL " + name)
}
// ============================================================
// Property Tests
// ============================================================
// Test: List reverse is involutive
fn testReverseInvolutive(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("reverse(reverse(xs)) == xs", true, count)
true
} else {
} else {
let xs = genIntList(0, 100, 20)
if List.reverse(List.reverse(xs)) == xs then
testReverseInvolutive(n - 1, count)
else {
if List.reverse(List.reverse(xs)) == xs then testReverseInvolutive(n - 1, count) else {
printResult("reverse(reverse(xs)) == xs", false, count - n + 1)
false
}
}
}
}
}
// Test: List reverse preserves length
fn testReverseLength(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("length(reverse(xs)) == length(xs)", true, count)
true
} else {
} else {
let xs = genIntList(0, 100, 20)
if List.length(List.reverse(xs)) == List.length(xs) then
testReverseLength(n - 1, count)
else {
if List.length(List.reverse(xs)) == List.length(xs) then testReverseLength(n - 1, count) else {
printResult("length(reverse(xs)) == length(xs)", false, count - n + 1)
false
}
}
}
}
}
// Test: List map preserves length
fn testMapLength(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("length(map(xs, f)) == length(xs)", true, count)
true
} else {
} else {
let xs = genIntList(0, 100, 20)
if List.length(List.map(xs, fn(x) => x * 2)) == List.length(xs) then
testMapLength(n - 1, count)
else {
if List.length(List.map(xs, fn(x: _) => x * 2)) == List.length(xs) then testMapLength(n - 1, count) else {
printResult("length(map(xs, f)) == length(xs)", false, count - n + 1)
false
}
}
}
}
}
// Test: List concat length is sum
fn testConcatLength(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("length(xs ++ ys) == length(xs) + length(ys)", true, count)
true
} else {
} else {
let xs = genIntList(0, 50, 10)
let ys = genIntList(0, 50, 10)
if List.length(List.concat(xs, ys)) == List.length(xs) + List.length(ys) then
testConcatLength(n - 1, count)
else {
if List.length(List.concat(xs, ys)) == List.length(xs) + List.length(ys) then testConcatLength(n - 1, count) else {
printResult("length(xs ++ ys) == length(xs) + length(ys)", false, count - n + 1)
false
}
}
}
}
}
// Test: Addition is commutative
fn testAddCommutative(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("a + b == b + a", true, count)
true
} else {
} else {
let a = genInt(-1000, 1000)
let b = genInt(-1000, 1000)
if a + b == b + a then
testAddCommutative(n - 1, count)
else {
if a + b == b + a then testAddCommutative(n - 1, count) else {
printResult("a + b == b + a", false, count - n + 1)
false
}
}
}
}
}
// Test: Multiplication is associative
fn testMulAssociative(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("(a * b) * c == a * (b * c)", true, count)
true
} else {
} else {
let a = genInt(-100, 100)
let b = genInt(-100, 100)
let c = genInt(-100, 100)
if (a * b) * c == a * (b * c) then
testMulAssociative(n - 1, count)
else {
if a * b * c == a * b * c then testMulAssociative(n - 1, count) else {
printResult("(a * b) * c == a * (b * c)", false, count - n + 1)
false
}
}
}
}
}
// Test: String concat length is sum
fn testStringConcatLength(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("length(s1 + s2) == length(s1) + length(s2)", true, count)
true
} else {
} else {
let s1 = genString(10)
let s2 = genString(10)
if String.length(s1 + s2) == String.length(s1) + String.length(s2) then
testStringConcatLength(n - 1, count)
else {
if String.length(s1 + s2) == String.length(s1) + String.length(s2) then testStringConcatLength(n - 1, count) else {
printResult("length(s1 + s2) == length(s1) + length(s2)", false, count - n + 1)
false
}
}
}
}
}
// Test: Zero is identity for addition
fn testAddIdentity(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("x + 0 == x && 0 + x == x", true, count)
true
} else {
} else {
let x = genInt(-10000, 10000)
if x + 0 == x && 0 + x == x then
testAddIdentity(n - 1, count)
else {
if x + 0 == x && 0 + x == x then testAddIdentity(n - 1, count) else {
printResult("x + 0 == x && 0 + x == x", false, count - n + 1)
false
}
}
}
}
}
// Test: Filter reduces or maintains length
fn testFilterLength(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("length(filter(xs, p)) <= length(xs)", true, count)
true
} else {
} else {
let xs = genIntList(0, 100, 20)
if List.length(List.filter(xs, fn(x) => x > 50)) <= List.length(xs) then
testFilterLength(n - 1, count)
else {
if List.length(List.filter(xs, fn(x: _) => x > 50)) <= List.length(xs) then testFilterLength(n - 1, count) else {
printResult("length(filter(xs, p)) <= length(xs)", false, count - n + 1)
false
}
}
}
}
}
// Test: Empty list is identity for concat
fn testConcatIdentity(n: Int, count: Int): Bool with {Console, Random} = {
if n <= 0 then {
printResult("concat(xs, []) == xs && concat([], xs) == xs", true, count)
true
} else {
} else {
let xs = genIntList(0, 100, 10)
if List.concat(xs, []) == xs && List.concat([], xs) == xs then
testConcatIdentity(n - 1, count)
else {
if List.concat(xs, []) == xs && List.concat([], xs) == xs then testConcatIdentity(n - 1, count) else {
printResult("concat(xs, []) == xs && concat([], xs) == xs", false, count - n + 1)
false
}
}
}
// ============================================================
// Main
// ============================================================
}
}
fn main(): Unit with {Console, Random} = {
Console.print("========================================")
@@ -234,7 +171,6 @@ fn main(): Unit with {Console, Random} = {
Console.print("")
Console.print("Running 100 iterations per property...")
Console.print("")
testReverseInvolutive(100, 100)
testReverseLength(100, 100)
testMapLength(100, 100)
@@ -245,7 +181,6 @@ fn main(): Unit with {Console, Random} = {
testAddIdentity(100, 100)
testFilterLength(100, 100)
testConcatIdentity(100, 100)
Console.print("")
Console.print("========================================")
Console.print(" All property tests completed!")

View File

@@ -1,39 +1,22 @@
// Demonstrating Random and Time effects in Lux
//
// Expected output (values will vary):
// Rolling dice...
// Die 1: <random 1-6>
// Die 2: <random 1-6>
// Die 3: <random 1-6>
// Coin flip: <true/false>
// Random float: <0.0-1.0>
// Current time: <timestamp>
// Roll a single die (1-6)
fn rollDie(): Int with {Random} = Random.int(1, 6)
// Roll multiple dice and print results
fn rollDice(count: Int): Unit with {Random, Console} = {
if count > 0 then {
let value = rollDie()
Console.print("Die " + toString(4 - count) + ": " + toString(value))
rollDice(count - 1)
} else {
} else {
()
}
}
}
// Main function demonstrating random effects
fn main(): Unit with {Random, Console, Time} = {
Console.print("Rolling dice...")
rollDice(3)
let coin = Random.bool()
Console.print("Coin flip: " + toString(coin))
let f = Random.float()
Console.print("Random float: " + toString(f))
let now = Time.now()
Console.print("Current time: " + toString(now))
}

View File

@@ -1,67 +1,41 @@
// Schema Evolution Demo
// Demonstrates version tracking and automatic migrations
// ============================================================
// PART 1: Type-Declared Migrations
// ============================================================
// Define a versioned type with a migration from v1 to v2
type User @v2 {
type User = {
name: String,
email: String,
// Migration from v1: add default email
from @v1 = { name: old.name, email: "unknown@example.com" }
}
// Create a v1 user
let v1_user = Schema.versioned("User", 1, { name: "Alice" })
let v1_version = Schema.getVersion(v1_user) // 1
// Migrate to v2 - uses the declared migration automatically
let v1_version = Schema.getVersion(v1_user)
let v2_user = Schema.migrate(v1_user, 2)
let v2_version = Schema.getVersion(v2_user) // 2
// ============================================================
// PART 2: Runtime Schema Operations (separate type)
// ============================================================
let v2_version = Schema.getVersion(v2_user)
// Create versioned values for a different type (no migration)
let config1 = Schema.versioned("Config", 1, "debug")
let config2 = Schema.versioned("Config", 2, "release")
// Check versions
let c1 = Schema.getVersion(config1) // 1
let c2 = Schema.getVersion(config2) // 2
let c1 = Schema.getVersion(config1)
let c2 = Schema.getVersion(config2)
// Migrate config (auto-migration since no explicit migration defined)
let upgradedConfig = Schema.migrate(config1, 2)
let upgradedConfigVersion = Schema.getVersion(upgradedConfig) // 2
// ============================================================
// PART 2: Practical Example - API Versioning
// ============================================================
let upgradedConfigVersion = Schema.getVersion(upgradedConfig)
// Simulate different API response versions
fn createResponseV1(data: String): { version: Int, payload: String } =
{ version: 1, payload: data }
fn createResponseV1(data: String): { version: Int, payload: String } = { version: 1, payload: data }
fn createResponseV2(data: String, timestamp: Int): { version: Int, payload: String, meta: { ts: Int } } =
{ version: 2, payload: data, meta: { ts: timestamp } }
fn createResponseV2(data: String, timestamp: Int): { version: Int, payload: String, meta: { ts: Int } } = { version: 2, payload: data, meta: { ts: timestamp } }
// Version-aware processing
fn getPayload(response: { version: Int, payload: String }): String =
response.payload
fn getPayload(response: { version: Int, payload: String }): String = response.payload
let resp1 = createResponseV1("Hello")
let resp2 = createResponseV2("World", 1234567890)
let payload1 = getPayload(resp1)
let payload2 = resp2.payload
// ============================================================
// RESULTS
// ============================================================
let payload2 = resp2.payload
fn main(): Unit with {Console} = {
Console.print("=== Schema Evolution Demo ===")

View File

@@ -1,58 +1,43 @@
// Shell/Process example - demonstrates the Process effect
//
// This script runs shell commands and uses environment variables
fn main(): Unit with {Process, Console} = {
Console.print("=== Lux Shell Example ===")
Console.print("")
// Get current working directory
let cwd = Process.cwd()
Console.print("Current directory: " + cwd)
Console.print("")
// Get environment variables
Console.print("Environment variables:")
match Process.env("USER") {
Some(user) => Console.print(" USER: " + user),
None => Console.print(" USER: (not set)")
}
None => Console.print(" USER: (not set)"),
}
match Process.env("HOME") {
Some(home) => Console.print(" HOME: " + home),
None => Console.print(" HOME: (not set)")
}
None => Console.print(" HOME: (not set)"),
}
match Process.env("SHELL") {
Some(shell) => Console.print(" SHELL: " + shell),
None => Console.print(" SHELL: (not set)")
}
None => Console.print(" SHELL: (not set)"),
}
Console.print("")
// Run shell commands
Console.print("Running shell commands:")
let date = Process.exec("date")
Console.print(" date: " + String.trim(date))
let kernel = Process.exec("uname -r")
Console.print(" kernel: " + String.trim(kernel))
let files = Process.exec("ls examples/*.lux | wc -l")
Console.print(" .lux files in examples/: " + String.trim(files))
Console.print("")
// Command line arguments
Console.print("Command line arguments:")
let args = Process.args()
let argCount = List.length(args)
if argCount == 0 then {
Console.print(" (no arguments)")
} else {
} else {
Console.print(" Count: " + toString(argCount))
match List.head(args) {
Some(first) => Console.print(" First: " + first),
None => Console.print(" First: (empty)")
}
}
None => Console.print(" First: (empty)"),
}
}
}
let result = run main() with {}

View File

@@ -1,15 +1,3 @@
// The "Ask" Pattern - Resumable Effects
//
// Unlike exceptions which unwind the stack, effect handlers can
// RESUME with a value. This enables "ask the environment" patterns.
//
// Expected output:
// Need config: api_url
// Got: https://api.example.com
// Need config: timeout
// Got: 30
// Configured with url=https://api.example.com, timeout=30
effect Config {
fn get(key: String): String
}
@@ -25,14 +13,13 @@ fn configure(): String with {Config, Console} = {
}
handler envConfig: Config {
fn get(key) =
if key == "api_url" then resume("https://api.example.com")
else if key == "timeout" then resume("30")
else resume("unknown")
fn get(key) = if key == "api_url" then resume("https://api.example.com") else if key == "timeout" then resume("30") else resume("unknown")
}
fn main(): Unit with {Console} = {
let result = run configure() with { Config = envConfig }
let result = run configure() with {
Config = envConfig,
}
Console.print(result)
}

View File

@@ -1,15 +1,3 @@
// Custom Logging with Effects
//
// This demonstrates how effects let you abstract side effects.
// The same code can be run with different logging implementations.
//
// Expected output:
// [INFO] Starting computation
// [DEBUG] x = 10
// [INFO] Processing
// [DEBUG] result = 20
// Final: 20
effect Log {
fn info(msg: String): Unit
fn debug(msg: String): Unit
@@ -26,18 +14,22 @@ fn computation(): Int with {Log} = {
}
handler consoleLogger: Log {
fn info(msg) = {
fn info(msg) =
{
Console.print("[INFO] " + msg)
resume(())
}
fn debug(msg) = {
}
fn debug(msg) =
{
Console.print("[DEBUG] " + msg)
resume(())
}
}
}
fn main(): Unit with {Console} = {
let result = run computation() with { Log = consoleLogger }
let result = run computation() with {
Log = consoleLogger,
}
Console.print("Final: " + toString(result))
}

View File

@@ -1,37 +1,18 @@
// Early Return with Fail Effect
//
// The Fail effect provides clean early termination.
// Functions declare their failure modes in the type signature.
//
// Expected output:
// Parsing "42"...
// Result: 42
// Parsing "100"...
// Result: 100
// Dividing 100 by 4...
// Result: 25
fn parsePositive(s: String): Int with {Fail, Console} = {
Console.print("Parsing \"" + s + "\"...")
if s == "42" then 42
else if s == "100" then 100
else Fail.fail("Invalid number: " + s)
if s == "42" then 42 else if s == "100" then 100 else Fail.fail("Invalid number: " + s)
}
fn safeDivide(a: Int, b: Int): Int with {Fail, Console} = {
Console.print("Dividing " + toString(a) + " by " + toString(b) + "...")
if b == 0 then Fail.fail("Division by zero")
else a / b
if b == 0 then Fail.fail("Division by zero") else a / b
}
fn main(): Unit with {Console} = {
// These succeed
let n1 = run parsePositive("42") with {}
Console.print("Result: " + toString(n1))
let n2 = run parsePositive("100") with {}
Console.print("Result: " + toString(n2))
let n3 = run safeDivide(100, 4) with {}
Console.print("Result: " + toString(n3))
}

View File

@@ -1,16 +1,3 @@
// Effect Composition - Combine multiple effects cleanly
//
// Unlike monad transformers (which have ordering issues),
// effects can be freely combined without boilerplate.
// Each handler handles its own effect, ignoring others.
//
// Expected output:
// [LOG] Starting computation
// Generated: 7
// [LOG] Processing value
// [LOG] Done
// Result: 14
effect Log {
fn log(msg: String): Unit
}
@@ -30,8 +17,8 @@ handler consoleLog: Log {
fn main(): Unit with {Console} = {
let result = run computation() with {
Log = consoleLog
}
Log = consoleLog,
}
Console.print("Generated: " + toString(result / 2))
Console.print("Result: " + toString(result))
}

View File

@@ -1,38 +1,19 @@
// Higher-Order Functions and Closures
//
// Functions are first-class values in Lux.
// Closures capture their environment.
//
// Expected output:
// Square of 5: 25
// Cube of 3: 27
// Add 10 to 5: 15
// Add 10 to 20: 30
// Composed: 15625 (cube(square(5)) = cube(25) = 15625)
fn apply(f: fn(Int): Int, x: Int): Int = f(x)
fn compose(f: fn(Int): Int, g: fn(Int): Int): fn(Int): Int =
fn(x: Int): Int => f(g(x))
fn compose(f: fn(Int): Int, g: fn(Int): Int): fn(Int): Int = fn(x: Int): Int => f(g(x))
fn square(n: Int): Int = n * n
fn cube(n: Int): Int = n * n * n
fn makeAdder(n: Int): fn(Int): Int =
fn(x: Int): Int => x + n
fn makeAdder(n: Int): fn(Int): Int = fn(x: Int): Int => x + n
fn main(): Unit with {Console} = {
// Apply functions
Console.print("Square of 5: " + toString(apply(square, 5)))
Console.print("Cube of 3: " + toString(apply(cube, 3)))
// Closures
let add10 = makeAdder(10)
Console.print("Add 10 to 5: " + toString(add10(5)))
Console.print("Add 10 to 20: " + toString(add10(20)))
// Function composition
let squareThenCube = compose(cube, square)
Console.print("Composed: " + toString(squareThenCube(5)))
}

View File

@@ -1,16 +1,3 @@
// Algebraic Data Types and Pattern Matching
//
// Lux has powerful ADTs with exhaustive pattern matching.
// The type system ensures all cases are handled.
//
// Expected output:
// Evaluating: (2 + 3)
// Result: 5
// Evaluating: ((1 + 2) * (3 + 4))
// Result: 21
// Evaluating: (10 - (2 * 3))
// Result: 4
type Expr =
| Num(Int)
| Add(Expr, Expr)
@@ -22,16 +9,16 @@ fn eval(e: Expr): Int =
Num(n) => n,
Add(a, b) => eval(a) + eval(b),
Sub(a, b) => eval(a) - eval(b),
Mul(a, b) => eval(a) * eval(b)
}
Mul(a, b) => eval(a) * eval(b),
}
fn showExpr(e: Expr): String =
match e {
Num(n) => toString(n),
Add(a, b) => "(" + showExpr(a) + " + " + showExpr(b) + ")",
Sub(a, b) => "(" + showExpr(a) + " - " + showExpr(b) + ")",
Mul(a, b) => "(" + showExpr(a) + " * " + showExpr(b) + ")"
}
Mul(a, b) => "(" + showExpr(a) + " * " + showExpr(b) + ")",
}
fn evalAndPrint(e: Expr): Unit with {Console} = {
Console.print("Evaluating: " + showExpr(e))
@@ -39,15 +26,10 @@ fn evalAndPrint(e: Expr): Unit with {Console} = {
}
fn main(): Unit with {Console} = {
// (2 + 3)
let e1 = Add(Num(2), Num(3))
evalAndPrint(e1)
// ((1 + 2) * (3 + 4))
let e2 = Mul(Add(Num(1), Num(2)), Add(Num(3), Num(4)))
evalAndPrint(e2)
// (10 - (2 * 3))
let e3 = Sub(Num(10), Mul(Num(2), Num(3)))
evalAndPrint(e3)
}

View File

@@ -1,14 +1,6 @@
// Factorial - compute n!
fn factorial(n: Int): Int = if n <= 1 then 1 else n * factorial(n - 1)
// Recursive version
fn factorial(n: Int): Int =
if n <= 1 then 1
else n * factorial(n - 1)
// Tail-recursive version (optimized)
fn factorialTail(n: Int, acc: Int): Int =
if n <= 1 then acc
else factorialTail(n - 1, n * acc)
fn factorialTail(n: Int, acc: Int): Int = if n <= 1 then acc else factorialTail(n - 1, n * acc)
fn factorial2(n: Int): Int = factorialTail(n, 1)

View File

@@ -1,22 +1,11 @@
// FizzBuzz - print numbers 1-100, but:
// - multiples of 3: print "Fizz"
// - multiples of 5: print "Buzz"
// - multiples of both: print "FizzBuzz"
fn fizzbuzz(n: Int): String =
if n % 15 == 0 then "FizzBuzz"
else if n % 3 == 0 then "Fizz"
else if n % 5 == 0 then "Buzz"
else toString(n)
fn fizzbuzz(n: Int): String = if n % 15 == 0 then "FizzBuzz" else if n % 3 == 0 then "Fizz" else if n % 5 == 0 then "Buzz" else toString(n)
fn printFizzbuzz(i: Int, max: Int): Unit with {Console} =
if i > max then ()
else {
if i > max then () else {
Console.print(fizzbuzz(i))
printFizzbuzz(i + 1, max)
}
}
fn main(): Unit with {Console} =
printFizzbuzz(1, 100)
fn main(): Unit with {Console} = printFizzbuzz(1, 100)
let output = run main() with {}

View File

@@ -1,42 +1,17 @@
// Number guessing game - demonstrates Random and Console effects
//
// Expected output:
// Welcome to the Guessing Game!
// Target number: 42
// Simulating guesses...
// Guess 50: Too high!
// Guess 25: Too low!
// Guess 37: Too low!
// Guess 43: Too high!
// Guess 40: Too low!
// Guess 41: Too low!
// Guess 42: Correct!
// Found in 7 attempts!
fn checkGuess(guess: Int, secret: Int): String = if guess == secret then "Correct" else if guess < secret then "Too low" else "Too high"
// Game logic - check a guess against the secret
fn checkGuess(guess: Int, secret: Int): String =
if guess == secret then "Correct"
else if guess < secret then "Too low"
else "Too high"
// Binary search simulation to find the number
fn binarySearch(low: Int, high: Int, secret: Int, attempts: Int): Int with {Console} = {
let mid = (low + high) / 2
let mid = low + high / 2
let result = checkGuess(mid, secret)
Console.print("Guess " + toString(mid) + ": " + result + "!")
if result == "Correct" then attempts
else if result == "Too low" then binarySearch(mid + 1, high, secret, attempts + 1)
else binarySearch(low, mid - 1, secret, attempts + 1)
if result == "Correct" then attempts else if result == "Too low" then binarySearch(mid + 1, high, secret, attempts + 1) else binarySearch(low, mid - 1, secret, attempts + 1)
}
fn main(): Unit with {Console} = {
Console.print("Welcome to the Guessing Game!")
// Use a fixed "secret" for reproducible output
let secret = 42
Console.print("Target number: " + toString(secret))
Console.print("Simulating guesses...")
let attempts = binarySearch(1, 100, secret, 1)
Console.print("Found in " + toString(attempts) + " attempts!")
}

View File

@@ -1,7 +1,3 @@
// The classic first program
// Expected output: Hello, World!
fn main(): Unit with {Console} =
Console.print("Hello, World!")
fn main(): Unit with {Console} = Console.print("Hello, World!")
let output = run main() with {}

View File

@@ -1,25 +1,14 @@
// Prime number utilities
fn isPrime(n: Int): Bool = if n < 2 then false else isPrimeHelper(n, 2)
fn isPrime(n: Int): Bool =
if n < 2 then false
else isPrimeHelper(n, 2)
fn isPrimeHelper(n: Int, i: Int): Bool = if i * i > n then true else if n % i == 0 then false else isPrimeHelper(n, i + 1)
fn isPrimeHelper(n: Int, i: Int): Bool =
if i * i > n then true
else if n % i == 0 then false
else isPrimeHelper(n, i + 1)
// Find first n primes
fn findPrimes(count: Int): Unit with {Console} =
findPrimesHelper(2, count)
fn findPrimes(count: Int): Unit with {Console} = findPrimesHelper(2, count)
fn findPrimesHelper(current: Int, remaining: Int): Unit with {Console} =
if remaining <= 0 then ()
else if isPrime(current) then {
if remaining <= 0 then () else if isPrime(current) then {
Console.print(toString(current))
findPrimesHelper(current + 1, remaining - 1)
}
else findPrimesHelper(current + 1, remaining)
} else findPrimesHelper(current + 1, remaining)
fn main(): Unit with {Console} = {
Console.print("First 20 prime numbers:")

View File

@@ -1,6 +1,3 @@
// Standard Library Demo
// Demonstrates the built-in modules: List, String, Option, Math
fn main(): Unit with {Console} = {
Console.print("=== List Operations ===")
let nums = [1, 2, 3, 4, 5]
@@ -11,7 +8,6 @@ fn main(): Unit with {Console} = {
Console.print("Length: " + toString(List.length(nums)))
Console.print("Reversed: " + toString(List.reverse(nums)))
Console.print("Range 1-5: " + toString(List.range(1, 6)))
Console.print("")
Console.print("=== String Operations ===")
let text = " Hello, World! "
@@ -22,7 +18,6 @@ fn main(): Unit with {Console} = {
Console.print("Contains 'World': " + toString(String.contains(text, "World")))
Console.print("Split by comma: " + toString(String.split("a,b,c", ",")))
Console.print("Join with dash: " + String.join(["x", "y", "z"], "-"))
Console.print("")
Console.print("=== Option Operations ===")
let some_val = Some(42)
@@ -31,7 +26,6 @@ fn main(): Unit with {Console} = {
Console.print("None mapped: " + toString(Option.map(none_val, fn(x: Int): Int => x * 2)))
Console.print("Some(42) getOrElse(0): " + toString(Option.getOrElse(some_val, 0)))
Console.print("None getOrElse(0): " + toString(Option.getOrElse(none_val, 0)))
Console.print("")
Console.print("=== Math Operations ===")
Console.print("abs(-5): " + toString(Math.abs(-5)))

View File

@@ -1,13 +1,3 @@
// State machine example using algebraic data types
// Demonstrates pattern matching for state transitions
//
// Expected output:
// Initial light: red
// After transition: green
// After two transitions: yellow
// Door: Closed -> Open -> Closed -> Locked
// Traffic light state machine
type TrafficLight =
| Red
| Yellow
@@ -17,24 +7,23 @@ fn nextLight(light: TrafficLight): TrafficLight =
match light {
Red => Green,
Green => Yellow,
Yellow => Red
}
Yellow => Red,
}
fn canGo(light: TrafficLight): Bool =
match light {
Green => true,
Yellow => false,
Red => false
}
Red => false,
}
fn lightColor(light: TrafficLight): String =
match light {
Red => "red",
Yellow => "yellow",
Green => "green"
}
Green => "green",
}
// Door state machine
type DoorState =
| Open
| Closed
@@ -52,27 +41,30 @@ fn applyAction(state: DoorState, action: DoorAction): DoorState =
(Open, CloseDoor) => Closed,
(Closed, LockDoor) => Locked,
(Locked, UnlockDoor) => Closed,
_ => state
}
_ => state,
}
fn doorStateName(state: DoorState): String =
match state {
Open => "Open",
Closed => "Closed",
Locked => "Locked"
}
Locked => "Locked",
}
// Test the state machines
let light1 = Red
let light2 = nextLight(light1)
let light3 = nextLight(light2)
let door1 = Closed
let door2 = applyAction(door1, OpenDoor)
let door3 = applyAction(door2, CloseDoor)
let door4 = applyAction(door3, LockDoor)
// Print results
fn printResults(): Unit with {Console} = {
Console.print("Initial light: " + lightColor(light1))
Console.print("After transition: " + lightColor(light2))

View File

@@ -1,8 +1,4 @@
// Stress test for RC system with large lists
// Tests FBIP optimization with single-owner chains
fn processChain(n: Int): Int = {
// Single owner chain - FBIP should reuse lists
let nums = List.range(1, n)
let doubled = List.map(nums, fn(x: Int): Int => x * 2)
let filtered = List.filter(doubled, fn(x: Int): Bool => x > n)
@@ -12,13 +8,10 @@ fn processChain(n: Int): Int = {
fn main(): Unit = {
Console.print("=== RC Stress Test ===")
// Run multiple iterations of list operations
let result1 = processChain(100)
let result2 = processChain(200)
let result3 = processChain(500)
let result4 = processChain(1000)
Console.print("Completed 4 chains")
Console.print("Sizes: 100, 200, 500, 1000")
}

View File

@@ -1,12 +1,7 @@
// Stress test for RC system WITH shared references
// Forces rc>1 path by keeping aliases
fn processWithAlias(n: Int): Int = {
let nums = List.range(1, n)
let alias = nums // This increments rc, forcing copy path
let _len = List.length(alias) // Use the alias
// Now nums has rc>1, so map must allocate new
let alias = nums
let _len = List.length(alias)
let doubled = List.map(nums, fn(x: Int): Int => x * 2)
let filtered = List.filter(doubled, fn(x: Int): Bool => x > n)
let reversed = List.reverse(filtered)
@@ -15,12 +10,9 @@ fn processWithAlias(n: Int): Int = {
fn main(): Unit = {
Console.print("=== RC Stress Test (Shared Refs) ===")
// Run multiple iterations with shared references
let result1 = processWithAlias(100)
let result2 = processWithAlias(200)
let result3 = processWithAlias(500)
let result4 = processWithAlias(1000)
Console.print("Completed 4 chains with shared refs")
}

View File

@@ -1,45 +1,25 @@
// Demonstrating tail call optimization (TCO) in Lux
// TCO allows recursive functions to run in constant stack space
//
// Expected output:
// factorial(20) = 2432902008176640000
// fib(30) = 832040
// sumTo(1000) = 500500
// countdown(10000) completed
// Factorial with accumulator - tail recursive
fn factorialTCO(n: Int, acc: Int): Int =
if n <= 1 then acc
else factorialTCO(n - 1, n * acc)
fn factorialTCO(n: Int, acc: Int): Int = if n <= 1 then acc else factorialTCO(n - 1, n * acc)
fn factorial(n: Int): Int = factorialTCO(n, 1)
// Fibonacci with accumulator - tail recursive
fn fibTCO(n: Int, a: Int, b: Int): Int =
if n <= 0 then a
else fibTCO(n - 1, b, a + b)
fn fibTCO(n: Int, a: Int, b: Int): Int = if n <= 0 then a else fibTCO(n - 1, b, a + b)
fn fib(n: Int): Int = fibTCO(n, 0, 1)
// Count down - simple tail recursion
fn countdown(n: Int): Int =
if n <= 0 then 0
else countdown(n - 1)
fn countdown(n: Int): Int = if n <= 0 then 0 else countdown(n - 1)
// Sum with accumulator - tail recursive
fn sumToTCO(n: Int, acc: Int): Int =
if n <= 0 then acc
else sumToTCO(n - 1, acc + n)
fn sumToTCO(n: Int, acc: Int): Int = if n <= 0 then acc else sumToTCO(n - 1, acc + n)
fn sumTo(n: Int): Int = sumToTCO(n, 0)
// Test the functions
let fact20 = factorial(20)
let fib30 = fib(30)
let sum1000 = sumTo(1000)
let countResult = countdown(10000)
// Print results
fn printResults(): Unit with {Console} = {
Console.print("factorial(20) = " + toString(fact20))
Console.print("fib(30) = " + toString(fib30))

View File

@@ -1,17 +1,8 @@
// This test shows FBIP optimization by comparing allocation counts
// With FBIP (rc=1): lists are reused in-place
// Without FBIP (rc>1): new lists are allocated
fn main(): Unit = {
Console.print("=== FBIP Allocation Test ===")
// Case 1: Single owner (FBIP active) - should reuse list
let a = List.range(1, 100)
let b = List.map(a, fn(x: Int): Int => x * 2)
let c = List.filter(b, fn(x: Int): Bool => x > 50)
let d = List.reverse(c)
Console.print("Single owner chain done")
// The allocation count will show FBIP is working
// if allocations are low relative to operations performed
}

View File

@@ -1,5 +1,4 @@
fn main(): Unit = {
// Test FBIP without string operations
let nums = [1, 2, 3, 4, 5]
let doubled = List.map(nums, fn(x: Int): Int => x * 2)
let filtered = List.filter(doubled, fn(x: Int): Bool => x > 4)

View File

@@ -1,6 +1,3 @@
// List Operations Test Suite
// Run with: lux test examples/test_lists.lux
fn test_list_length(): Unit with {Test} = {
Test.assertEqual(0, List.length([]))
Test.assertEqual(1, List.length([1]))

View File

@@ -1,6 +1,3 @@
// Math Test Suite
// Run with: lux test examples/test_math.lux
fn test_addition(): Unit with {Test} = {
Test.assertEqual(4, 2 + 2)
Test.assertEqual(0, 0 + 0)

View File

@@ -1,21 +1,10 @@
// Test demonstrating ownership transfer with aliases
// The ownership transfer optimization ensures FBIP still works
// even when variables are aliased, because ownership is transferred
// rather than reference count being incremented.
fn main(): Unit = {
Console.print("=== Ownership Transfer Test ===")
let a = List.range(1, 100)
// Ownership transfers from 'a' to 'alias', keeping rc=1
let alias = a
let len1 = List.length(alias)
// Since ownership transferred, 'a' still has rc=1
// FBIP can still optimize map/filter/reverse
let b = List.map(a, fn(x: Int): Int => x * 2)
let c = List.filter(b, fn(x: Int): Bool => x > 50)
let d = List.reverse(c)
Console.print("Ownership transfer chain done")
}

View File

@@ -1,17 +1,13 @@
fn main(): Unit = {
Console.print("=== Allocation Comparison ===")
// FBIP path (rc=1): list is reused
Console.print("Test 1: FBIP path")
let a1 = List.range(1, 50)
let b1 = List.map(a1, fn(x: Int): Int => x * 2)
let c1 = List.reverse(b1)
Console.print("FBIP done")
// To show non-FBIP, we need concat which doesn't have FBIP
Console.print("Test 2: Non-FBIP path (concat)")
let x = List.range(1, 25)
let y = List.range(26, 50)
let z = List.concat(x, y) // concat always allocates new
let z = List.concat(x, y)
Console.print("Concat done")
}

View File

@@ -1,21 +1,11 @@
// Demonstrating type classes (traits) in Lux
//
// Expected output:
// RGB color: rgb(255,128,0)
// Red color: red
// Green color: green
// Define a simple Printable trait
trait Printable {
fn format(value: Int): String
}
// Implement Printable
impl Printable for Int {
fn format(value: Int): String = "Number: " + toString(value)
}
// A Color type with pattern matching
type Color =
| Red
| Green
@@ -27,15 +17,15 @@ fn colorName(c: Color): String =
Red => "red",
Green => "green",
Blue => "blue",
RGB(r, g, b) => "rgb(" + toString(r) + "," + toString(g) + "," + toString(b) + ")"
}
RGB(r, g, b) => "rgb(" + toString(r) + "," + toString(g) + "," + toString(b) + ")",
}
// Test
let myColor = RGB(255, 128, 0)
let redColor = Red
let greenColor = Green
// Print results
fn printResults(): Unit with {Console} = {
Console.print("RGB color: " + colorName(myColor))
Console.print("Red color: " + colorName(redColor))

View File

@@ -1,15 +1,3 @@
// Demonstrating Schema Evolution in Lux
//
// Lux provides versioned types to help manage data evolution over time.
// The Schema module provides functions for creating and migrating versioned values.
//
// Expected output:
// Created user v1: Alice (age unknown)
// User version: 1
// Migrated to v2: Alice (age unknown)
// User version after migration: 2
// Create a versioned User value at v1
fn createUserV1(name: String): Unit with {Console} = {
let user = Schema.versioned("User", 1, { name: name })
let version = Schema.getVersion(user)
@@ -17,7 +5,6 @@ fn createUserV1(name: String): Unit with {Console} = {
Console.print("User version: " + toString(version))
}
// Migrate a user to v2
fn migrateUserToV2(name: String): Unit with {Console} = {
let userV1 = Schema.versioned("User", 1, { name: name })
let userV2 = Schema.migrate(userV1, 2)
@@ -26,7 +13,6 @@ fn migrateUserToV2(name: String): Unit with {Console} = {
Console.print("User version after migration: " + toString(newVersion))
}
// Main
fn main(): Unit with {Console} = {
createUserV1("Alice")
migrateUserToV2("Alice")

View File

@@ -1,54 +1,30 @@
// Simple Counter for Browser
// Compile with: lux compile examples/web/counter.lux --target js -o examples/web/counter.js
type Model =
| Counter(Int)
// ============================================================================
// Model
// ============================================================================
type Model = | Counter(Int)
fn getCount(m: Model): Int = match m { Counter(n) => n }
fn getCount(m: Model): Int =
match m {
Counter(n) => n,
}
fn init(): Model = Counter(0)
// ============================================================================
// Messages
// ============================================================================
type Msg = | Increment | Decrement | Reset
// ============================================================================
// Update
// ============================================================================
type Msg =
| Increment
| Decrement
| Reset
fn update(model: Model, msg: Msg): Model =
match msg {
Increment => Counter(getCount(model) + 1),
Decrement => Counter(getCount(model) - 1),
Reset => Counter(0)
}
// ============================================================================
// View - Returns HTML string for simplicity
// ============================================================================
Reset => Counter(0),
}
fn view(model: Model): String = {
let count = getCount(model)
"<div class=\"counter\">" +
"<h1>Lux Counter</h1>" +
"<div class=\"display\">" + toString(count) + "</div>" +
"<div class=\"buttons\">" +
"<button onclick=\"dispatch('Decrement')\">-</button>" +
"<button onclick=\"dispatch('Reset')\">Reset</button>" +
"<button onclick=\"dispatch('Increment')\">+</button>" +
"</div>" +
"</div>"
"<div class=\"counter\">" + "<h1>Lux Counter</h1>" + "<div class=\"display\">" + toString(count) + "</div>" + "<div class=\"buttons\">" + "<button onclick=\"dispatch('Decrement')\">-</button>" + "<button onclick=\"dispatch('Reset')\">Reset</button>" + "<button onclick=\"dispatch('Increment')\">+</button>" + "</div>" + "</div>"
}
// ============================================================================
// Export for browser runtime
// ============================================================================
fn luxInit(): Model = init()
fn luxUpdate(model: Model, msgName: String): Model =
@@ -56,7 +32,7 @@ fn luxUpdate(model: Model, msgName: String): Model =
"Increment" => update(model, Increment),
"Decrement" => update(model, Decrement),
"Reset" => update(model, Reset),
_ => model
}
_ => model,
}
fn luxView(model: Model): String = view(model)