A strongly-typed, functional programming language for modeling and executing business logic with precision and clarity
Walnut is a modern functional programming language that combines powerful type system features with practical programming constructs. Designed for building robust applications, Walnut emphasizes type safety, immutability, and clear error handling while maintaining excellent developer ergonomics.
- π― Expressive Type System - Set-theory based types with union, intersection, and refinement types
- π Type Safety - Strong static type checking with comprehensive type inference
- β‘ Functional Core - Immutability by default with first-class functions and lambda expressions
- π Built-in Dependency Injection - Compile-time dependency resolution and service management
- π‘οΈ Sophisticated Error Handling - Result types with automatic error propagation
- π§ Method-Oriented Design - Behavior-driven functions attached to types
- π¦ Module System - Package-based organization with explicit dependency management
- π JSON Integration - First-class support for JSON parsing and type-safe hydration
Choose your installation method:
Download the latest CLI bundle (includes everything needed):
Extract and run:
tar -xzf walnut-cli.tar.gz
cd walnut-cli-bundle
./walnut.phar hello-worldcomposer require walnut/lang
./vendor/bin/walnut hello-worldDownload the server bundle for your platform:
# Linux
tar -xzf walnut-roadrunner-linux-amd64.tar.gz
cd walnut-roadrunner-linux-amd64
./walnut-roadrunner --port 8084
# macOS (Intel)
tar -xzf walnut-roadrunner-darwin-amd64.tar.gz
cd walnut-roadrunner-darwin-amd64
./walnut-roadrunner --port 8084
# macOS (Apple Silicon)
tar -xzf walnut-roadrunner-darwin-arm64.tar.gz
cd walnut-roadrunner-darwin-arm64
./walnut-roadrunner --port 8084Create a file hello.nut:
module hello:
=> 'Hello, World!';
Run it:
# Using standalone phar
./walnut.phar hello
# Using composer installation
./vendor/bin/walnut hello
# Development server with live reload
./walnut.phar serve --port 3000Walnut features one of the most expressive type systems among programming languages:
/* Refined types with constraints */
Age := Integer<0..150>;
Email := String<5..254> @ InvalidEmail :: /* Custom email validation */;
NonEmptyStringArray := Array<String, 1..>;
/* Union types in different forms */
MyResult := [status: String['success'], data: Any]
| [status: String['error'], message: String];
/* Sealed types for data integrity */
User := $[id: Integer<1..>, name: String<1..>, email: Email];
/* Enumerations with pattern matching */
Status := (Pending, Active, Completed);
First-class functions, immutability, and powerful transformation operations:
/* Lambda functions with named parameters */
double = ^x: Integer => Integer :: x * 2;
/* Array transformations */
numbers = [1, 2, 3, 4, 5];
doubled = numbers->map(double);
evens = numbers->filter(^i: Integer => Boolean :: i % 2 == 0);
/* Function composition */
processData = ^data: Array<Integer> ::
data->filter(^x: Integer => Boolean :: x > 0)
->map(^x: Integer :: x * 2);
processed = processData([0, 1, -2, 3, -4, 5]);
/* Result: [2, 6, 10] */
Type-safe error handling without exceptions:
Age = Integer<0..150>;
/* Result type for operations that may fail */
parseAge = ^input: String => Result<Age, NotANumber|String> :: {
num = input => asInteger; /* Propagates NotANumber error automatically */
?whenTypeOf(num) is {
`Age: num,
~: => @'Age must be between 0 and 150'
}
};
/* Pattern matching on results */
result = parseAge('25');
?whenIsError(result) { 'Could not parse age: ' + result->printed };
Attach behavior to types with methods:
/* Type definition */
Point := [x: Real, y: Real];
/* Methods on Point */
Point->distanceTo(^p: Point => Real<0..>) :: {
dx = $x - p.x;
dy = $y - p.y;
dxSquared = dx * dx;
dySquared = dy * dy;
sum = dxSquared + dySquared;
sum->sqrt
};
Point->translate(^delta: [dx: Real, dy: Real] => Point) :: {
Point![x: $x + delta.dx, y: $y + delta.dy]
};
/* Usage */
p1 = Point![x: 0.0, y: 0.0];
p2 = Point![x: 3.0, y: 4.0];
distance = p1->distanceTo(p2); /* 5.0 */
translated = p1->translate([dx: 1.0, dy: 2.0]); /* [x: 1.0, y: 2.0] */
Convert external data to typed values with validation:
/* Define your data structure */
Email := #String<5..254> @ InvalidEmail :: /* Custom email validation */;
UserInput := $[
username: String<3..20>,
email: Email,
age: Integer<13..>
];
/* Hydrate from JSON with automatic validation */
jsonData = '{"username":"alice","email":"[email protected]","age":25}';
result = jsonData->jsonDecode => hydrateAs(`UserInput);
?whenIsError(result) {
'Hydration failed: ' + result->printed
} ~ {
processUser(result)
};
Every function or method can declare dependencies that are automatically resolved at compile time:
/* The type to be injected */
ProjectById = ^ ~ProjectId => Result<Project, ProjectNotFound>;
/* Injected implementation */
==> ProjectById %% db: DatabaseConnection :: ... use db to fetch project ... ;
/* Using the injected function */
markProjectDone = ^id: ProjectId => Result<Null, ProjectNotFound> %% byId: ProjectById :: {
project = byId=>invoke(id); /* injected function called */
project->markDone;
...
};
Walnut comes with comprehensive documentation organized into 5 major parts:
Part I: Fundamentals
- Lexical Structure - Tokens, keywords, operators
- Type System - Type hierarchy and subtyping rules
- Values and Literals - Literal syntax and type inference
Part II: Type Definitions
- User-Defined Types - Atoms, enumerations, data types
- Type Refinement - Constraints and value subsets
- Integers and Reals - Numeric types and operations
- Strings - String operations and methods
- Booleans - Boolean logic and operations
- Arrays and Tuples - Collection types
- Maps and Records - Key-value structures
- Union and Intersection Types - Complex type compositions
- Mutable Values - Controlled mutability
- Reflection and Metaprogramming - Type introspection
Part III: Functions, Methods, and Control Flow
- Functions - Function syntax and parameters
- Methods - Method definitions and resolution
- Constructors and Casts - Type conversions
- Expressions - Expression categories
- Conditional Expressions - Pattern matching
- Early Returns and Error Handling - Error propagation
Part IV: Built-in Library
- Core Methods - Built-in operations on all types
- Standard Library Types - Clock, Random, File, HTTP, Database
Part V: Advanced Features
- Hydration - Runtime type conversion and validation
- Module System - Code organization
- Dependency Injection - Service management
- Entry Points - CLI and HTTP interfaces
- Testing - Test framework
- Templates - HTML template system
module user-service %% $http/router, $db/connector:
User := $[id: Integer<1..>, username: String<3..20>, email: String];
createUser = ^[username: String, email: String] => *Result<User, String> :: {
/* Validate input */
?when(#username->length < 3) {
=> @'Username too short'
};
/* Insert into database */
sql = 'INSERT INTO users (username, email) VALUES (?, ?)';
%databaseConnector |> execute(sql);
/* Return created user */
User[id: 1, username: #username, email: #email]
};
handleRequest = ^{HttpRequest} => {HttpResponse} :: {
request = $->shape(`HttpRequest);
?whenValueOf(request.method) is {
HttpRequestMethod.post: {
userData = request.body->jsonDecode => hydrateAs(`[username: String, email: String]);
result = createUser[username: userData.username, email: userData.email];
?whenTypeOf(result) is {
`User: HttpResponse[status: 201, headers: [:], body: result->jsonStringify],
`Error: HttpResponse[status: 400, headers: [:], body: [error: result->error]->jsonStringify]
}
},
~: HttpResponse[status: 405, headers: [:], body: 'Method not allowed']
}
};
module analytics:
Transaction := [id: Integer, amount: Real, category: String];
analyzeTransactions = ^transactions: Array<Transaction> :: {
total = transactions->map(^t: Transaction => Real :: t.amount)->sum;
/* Get unique categories */
categories = transactions->map(^t: Transaction => String :: t.category)->unique;
/* Calculate total per category */
categoryTotals = categories->map(^cat: String :: [
category: cat,
total: transactions
->filter(^t: Transaction => Boolean :: t.category == cat)
->map(^t: Transaction => Real :: t.amount)
->sum
]);
[total: total, byCategory: categoryTotals]
};
=> {
transactions = [
[id: 1, amount: 100.0, category: 'food'],
[id: 2, amount: 50.0, category: 'transport'],
[id: 3, amount: 75.0, category: 'food']
];
result = analyzeTransactions(transactions);
result->printed
/* Output: [total: 225.0, byCategory: [...]] */
};
- π Online Demos - Try Walnut in your browser
- π¦ Example Projects - Downloadable demo applications
- π Full Documentation - Complete language specification
- π Issue Tracker - Report bugs and request features
walnut-lang/
βββ cli/ # CLI entry point
βββ core-nut-lib/ # Core standard library (Walnut code)
βββ docs/ # Complete language documentation
β βββ 00-index.md # Documentation index
β βββ 01-lexical-structure.md
β βββ ...
β βββ 27-templates.md
βββ src/ # PHP implementation
βββ walnut-src/ # Example Walnut programs
βββ tests/ # Test suite
Walnut is designed around several core principles:
- Type Safety First - Catch errors at compile time, not runtime
- Immutability by Default - Predictable, side-effect-free code
- Explicit Over Implicit - Clear intent and dependencies
- Business Logic Focus - Express domain models precisely
- Developer Ergonomics - Concise syntax without sacrificing clarity
Walnut is available in two independent distributions:
- Size: 3.0 MB
- For: Development, testing, scripts
- Features: CLI execution, testing framework, development HTTP server
- Download: From GitHub Releases
- Size: 18-19 MB (platform-specific)
- For: Production HTTP servers
- Features: High-performance RoadRunner server, multiple workers
- Platforms: Linux x86-64, macOS Intel, macOS Apple Silicon
- Download: From GitHub Releases
Why separate? The CLI doesn't need RoadRunner code, so we keep it lightweight. The server bundle is self-contained and ready to deploy.
Contributions are welcome! Please feel free to submit pull requests, report bugs, or suggest features through the issue tracker.
Walnut Language is open-source software licensed under the MIT license.
Walnut draws inspiration from functional languages like Haskell and ML, type systems from TypeScript and Flow, and practical features from modern languages like Rust and Kotlin.
Ready to start? Check out the Complete Documentation or try the Online Demos!