walnut / lang
Installs: 24
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/walnut/lang
Requires
- php: >=8.4
- ext-bcmath: *
- ext-mbstring: *
- kapitancho/walex: ^0.0.1
Requires (Dev)
- phpunit/phpunit: ^11.0.5
README
A strongly-typed, functional programming language for modeling and executing business logic with precision and clarity
Overview
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.
Key Features
- 🎯 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
Quick Start
Installation
Install Walnut via Composer:
composer require walnut/lang
Hello World
Create a file hello.nut:
module hello:
>>> 'Hello, World!';
Run it from PHP:
php -f cli/index.php hello
Language Highlights
Powerful Type System
Walnut 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);
Functional Programming
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] */
Error Handling with Result Types
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 };
Method-Oriented Design
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] */
Type-Safe JSON Hydration
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":"alice@example.com","age":25}';
result = jsonData->jsonDecode => hydrateAs(`UserInput);
?whenIsError(result) {
'Hydration failed: ' + result->printed
} ~ {
processUser(result)
};
Built-in Dependency Injection
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;
...
};
Documentation
Walnut comes with comprehensive documentation organized into 5 major parts:
📚 Complete Language Specification
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
Examples
Web Service Example
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']
}
};
Data Processing Pipeline
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: [...]] */
};
Resources
- 🌐 Online Demos - Try Walnut in your browser
- 📦 Example Projects - Downloadable demo applications
- 📖 Full Documentation - Complete language specification
- 🐛 Issue Tracker - Report bugs and request features
Project Structure
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
Philosophy
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
Contributing
Contributions are welcome! Please feel free to submit pull requests, report bugs, or suggest features through the issue tracker.
License
Walnut Language is open-source software licensed under the MIT license.
Acknowledgments
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!