Build from Source
Lambda Prelude is built from OCaml source with dune.
# Requires: OCaml 5.4+, dune 3.0+, menhir 2.1+
git clone <repo-url> lambda_prelude
cd lambda_prelude
dune build
On Windows, the binary is a true native MinGW-w64 executable — no Cygwin DLL at runtime. Source disclosure is under NDA; please get in touch before evaluating for production.
Hello, Prelude
Create hello.lp:
'Hello, Lambda Prelude!' printNl.
Run it under the interpreter:
lambda-prelude run hello.lp
Build it as a native binary:
lambda-prelude build hello.lp --out hello
./hello
The interpreter is for iteration. The AOT binary is the semantic record — when interpreter and AOT disagree, the AOT binary wins.
A Counter Class
Lambda Prelude is functional: values are immutable and classes do not declare instance variables. Each object is an immutable record over fields:.
Object subclass: #Counter fields: (value).
Counter class >> of: n = Counter fields: { value: n }.
Counter >> value = value.
Counter >> inc = Counter fields: { value: value + 1 }.
c := Counter of: 41.
c inc value printNl. "=> 42"
inc returns a new Counter. There is no := reassignment in user code — the only binding form is let, written as := at top-level statements.
Branching is Polymorphic Dispatch
There is no if/match at the surface. Branching is done through messages:
(score > 90)
ifTrue: ['A' printNl]
ifFalse: ['B' printNl].
name ifPresent: [:n | n printNl]
ifAbsent: ['anonymous' printNl].
xs ifEmpty: ['empty list' printNl]
ifNotEmpty: [:h :t | h printNl].
This is the same convention used by traditional Smalltalk, applied uniformly: every conditional, every option / list destructuring, every retry / timeout branch is a message send.
Protocols Replace Inheritance
Classes do not inherit. Shared behaviour is expressed as Protocols, which act like type classes. A class declares the protocols it satisfies in its protocols: clause.
Protocol subclass: #Comparable
requires: (#<).
Comparable >> > other = other < self.
Comparable >> min: o = (self < o) ifTrue: [self] ifFalse: [o].
Comparable >> max: o = (self < o) ifTrue: [o] ifFalse: [self].
Object subclass: #Score
fields: (points)
protocols: (Comparable).
Score class >> of: n = Score fields: { points: n }.
Score >> points = points.
Score >> < other = points < other points.
((Score of: 10) max: (Score of: 3)) printNl.
Score implements <; >, min:, and max: come from Comparable for free.
Two Execution Modes
The same source runs two ways. They share the standard library, the type system, and the actor model.
| Capability | interpreter | AOT |
|---|---|---|
| Tree-walk for development iteration | yes | — |
| Direct OCaml calls for statically resolvable sends | — | yes |
| Runtime dispatcher for dynamic sends | yes | yes |
| Multi-domain work-stealing scheduler | yes | yes |
Plugins via Dynlink (PostgreSQL, MariaDB, MySQL, Redis) | yes | yes |
Use run for iteration. Use build for production — the AOT binary lowers statically resolvable sends to direct OCaml calls and routes the rest through runtime method dispatch.
CLI Reference
lambda-prelude run script.lp # tree-walk interpreter
lambda-prelude build script.lp --out binary # AOT to native
lambda-prelude test tests # run Test API specs
lambda-prelude new my-service # scaffold a project
Debug tooling:
lambda-prelude run script.lp --trace-mailbox # log every mailbox enqueue / receive
lambda-prelude run script.lp --quiet # suppress unmatched-message warnings
lambda-prelude run script.lp --scheduler multi 4 # N-worker domain pool + auto-distribute
lambda-prelude build script.lp --emit # print the lowered OCaml to stdout
lambda-prelude build script.lp --out script.ml # write the lowered OCaml to a fileNext Steps
- Examples — 112 runnable Lambda Prelude files
- Actors — mailbox, selective receive, supervision
- AOT — how Lambda Prelude source becomes a native binary
- API Reference — built-in classes and standard library