feat: add module import examples and standard library

Module system was already implemented - this adds examples and stdlib:

examples/modules/:
- math_utils.lux: Reusable math functions (square, cube, factorial)
- string_utils.lux: String utilities (repeat, exclaim, greet)
- main.lux: Basic module import example
- main_selective.lux: Selective imports {fn1, fn2}
- main_wildcard.lux: Wildcard imports (module.*)
- use_stdlib.lux: Using the standard library

std/:
- prelude.lux: Core utilities (identity, compose, flip, not, and, or)
- io.lux: I/O helpers (println, readLine, debug)
- option.lux: Option utilities (some, none, map, flatMap, filter)
- result.lux: Result utilities (ok, err, mapOk, mapErr)

Import syntax supports:
- import path/to/module       (access as module.fn)
- import path/to/module as x  (access as x.fn)
- import path/to/module.{a,b} (access as a, b directly)
- import path/to/module.*     (all exports directly)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 17:28:23 -05:00
parent 0b5abece5f
commit 9ee7148d24
10 changed files with 264 additions and 0 deletions

20
examples/modules/main.lux Normal file
View File

@@ -0,0 +1,20 @@
// 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))
}
let output = run main() with {}

View File

@@ -0,0 +1,17 @@
// 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"))
}
let output = run main() with {}

View File

@@ -0,0 +1,14 @@
// 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)))
Console.print("sumRange(1, 4) = " + toString(sumRange(1, 4)))
}
let output = run main() with {}

View File

@@ -0,0 +1,14 @@
// Math utilities module
// Exports: square, cube, factorial
pub fn square(n: Int): Int = n * n
pub fn cube(n: Int): Int = n * n * n
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)

View File

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

View File

@@ -0,0 +1,23 @@
// 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)))
Console.print("isNone(None) = " + toString(opt.isNone(y)))
Console.print("unwrapOr(Some(10), 0) = " + toString(opt.unwrapOr(x, 0)))
Console.print("unwrapOr(None, 0) = " + toString(opt.unwrapOr(y, 0)))
}
let output = run main() with {}

28
std/io.lux Normal file
View File

@@ -0,0 +1,28 @@
// Standard I/O utilities
// Wraps Console effect with convenient functions
/// Print a line with a newline
pub fn println(s: String): Unit with {Console} =
Console.print(s)
/// Print without newline (if supported)
pub fn print(s: String): Unit with {Console} =
Console.print(s)
/// Read a line from input
pub fn readLine(): String with {Console} =
Console.readLine()
/// Read an integer from input
pub fn readInt(): Int with {Console} =
Console.readInt()
/// Print a debug representation of any value
pub fn debug<T>(label: String, value: T): T with {Console} = {
Console.print(label + ": " + toString(value))
value
}
/// Print multiple strings on separate lines
pub fn printAll(lines: List<String>): Unit with {Console} =
List.fold(lines, (), fn(acc: Unit, line: String): Unit with {Console} => Console.print(line))

57
std/option.lux Normal file
View File

@@ -0,0 +1,57 @@
// Option type utilities
// For working with optional values
/// Wrap a value in Some
pub fn some<T>(value: T): Option<T> = Some(value)
/// The None value
pub fn none<T>(): Option<T> = None
/// Check if option has a value
pub fn isSome<T>(opt: Option<T>): Bool =
match opt {
Some(_) => true,
None => false
}
/// Check if option is empty
pub fn isNone<T>(opt: Option<T>): Bool =
match opt {
Some(_) => false,
None => true
}
/// Get value or default
pub fn unwrapOr<T>(opt: Option<T>, default: T): T =
match opt {
Some(v) => v,
None => default
}
/// Map over the value if present
pub fn map<T, U>(opt: Option<T>, f: fn(T): U): Option<U> =
match opt {
Some(v) => Some(f(v)),
None => None
}
/// FlatMap (bind) for options
pub fn flatMap<T, U>(opt: Option<T>, f: fn(T): Option<U>): Option<U> =
match opt {
Some(v) => f(v),
None => None
}
/// Filter option by predicate
pub fn filter<T>(opt: Option<T>, pred: fn(T): Bool): Option<T> =
match opt {
Some(v) => if pred(v) then Some(v) else None,
None => None
}
/// Convert Option to List (empty or singleton)
pub fn toList<T>(opt: Option<T>): List<T> =
match opt {
Some(v) => [v],
None => []
}

37
std/prelude.lux Normal file
View File

@@ -0,0 +1,37 @@
// Standard Prelude - commonly used functions and types
// This module can be imported to get essential utilities
/// Identity function - returns its argument unchanged
pub fn identity<T>(x: T): T = x
/// Constant function - returns first argument, ignores second
pub fn const<A, B>(a: A, b: B): A = a
/// Function composition
pub fn compose<A, B, C>(f: fn(B): C, g: fn(A): B): fn(A): C =
fn(x: A): C => f(g(x))
/// Flip argument order of a binary function
pub fn flip<A, B, C>(f: fn(A, B): C): fn(B, A): C =
fn(b: B, a: A): C => f(a, b)
/// Apply a function to a value (useful for pipelines)
pub fn apply<A, B>(f: fn(A): B, x: A): B = f(x)
/// Check if two integers are equal
pub fn eq(a: Int, b: Int): Bool = a == b
/// Check if first is less than second
pub fn lt(a: Int, b: Int): Bool = a < b
/// Check if first is greater than second
pub fn gt(a: Int, b: Int): Bool = a > b
/// Negate a boolean
pub fn not(b: Bool): Bool = if b then false else true
/// Logical and
pub fn and(a: Bool, b: Bool): Bool = if a then b else false
/// Logical or
pub fn or(a: Bool, b: Bool): Bool = if a then true else b

43
std/result.lux Normal file
View File

@@ -0,0 +1,43 @@
// Result type utilities
// For working with computations that may fail
/// Wrap a value in Ok
pub fn ok<T, E>(value: T): Result<T, E> = Ok(value)
/// Wrap an error in Err
pub fn err<T, E>(error: E): Result<T, E> = Err(error)
/// Check if result is Ok
pub fn isOk<T, E>(r: Result<T, E>): Bool =
match r {
Ok(_) => true,
Err(_) => false
}
/// Check if result is Err
pub fn isErr<T, E>(r: Result<T, E>): Bool =
match r {
Ok(_) => false,
Err(_) => true
}
/// Get value or default
pub fn unwrapOr<T, E>(r: Result<T, E>, default: T): T =
match r {
Ok(v) => v,
Err(_) => default
}
/// Map over the success value
pub fn mapOk<T, U, E>(r: Result<T, E>, f: fn(T): U): Result<U, E> =
match r {
Ok(v) => Ok(f(v)),
Err(e) => Err(e)
}
/// Map over the error value
pub fn mapErr<T, E, F>(r: Result<T, E>, f: fn(E): F): Result<T, F> =
match r {
Ok(v) => Ok(v),
Err(e) => Err(f(e))
}