Lambda Prelude
関数型 Smalltalk を AOT でネイティブバイナリへ — スーパーバイザツリーを添えて
ネイティブ AOT
lambda-prelude build でネイティブバイナリを生成。LP ソースを OCaml に変換し、ocamlopt でネイティブコンパイルする。生成バイナリには LP のランタイムが同梱される。静的に解決できる送信は直接呼び出しになり、それ以外は実行時のメソッドディスパッチを通る。バイトコード VM も JIT も持たない。
Effects ベースのアクター
spawn / send / 選択受信 / タイムアウト / Future / ask: / リンク / モニタ / スーパーバイザ。OCaml 5 のエフェクトハンドラ上に直接構築。Eio・Miou・POSIX 専用 API には依存しない。Windows と Linux 両対応。
関数型 Smalltalk
表層は Smalltalk のように読めるが、値は不変・let 束縛のみで、プロトコル制約付き Hindley-Milner で型推論される。アクター行多相にも対応。型注釈は任意。
サービス向け標準装備
HTTP サーバ / クライアント、TLS ソケット、JSON、JSON-RPC、TERIOS RPC、SQLite、PostgreSQL、MariaDB / MySQL、Redis / Valkey、TORM、AES-256-GCM、Argon2id、SHA-256 / SHA-512、HMAC-SHA-256。
想定用途
Lambda Prelude が狙うのは、バックエンドの 中核として常駐する サービスであって、TUI や GUI、Web などのユーザインタフェースを作る用途は対象外。
- HTTP API サーバ
- 分散 RPC サービス (JSON-RPC または TERIOS RPC)
- ワーカーアクター、キュー、セッション管理
- スーパーバイザツリーに支えられた常駐プロセス
- ファイル / データベース / 外部 HTTP / サブプロセスを呼び出す業務バッチ
- TERIOS RPC の request / response エンベロープを使う業務サービス
- テスト → AOT ビルド → ネイティブ実行を一気通貫で回せる小さなサービス単位
設計の中心はオブジェクト。継承階層は避け、値は不変、共有はプロトコル経由、可変状態はアクターのループ引数に閉じ、失敗は明示的なエラーかスーパーバイザ通知として扱う。
カウンタ
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.
値は不変。inc は新しい Counter を返す。:= による再代入はなく、let 束縛のみ。
アクター
parent := Actor self.
child := Actor spawn: [:me |
msg := me receive.
msg printNl.
parent ! #pong
].
child ! #ping.
parent receive printNl.
メールボックス、FIFO 受信、選択受信、タイムアウト、リンク、モニタ、終了シグナルの捕捉、スーパーバイザツリー — すべて OCaml 5 のエフェクトハンドラの上に乗る。
ビルド
lambda-prelude build はネイティブ実行ファイルを出力する。LP ソースを OCaml ソースへ変換し、ocamlopt でネイティブコンパイルする。生成バイナリには LP のランタイム(値表現・アクタースケジューラ・組込メソッド・メソッドディスパッチ経路)が一緒にコンパイルされる。静的にレシーバが特定できる送信は直接の関数呼び出しになり、特定できない送信(リフレクション / リモート / プラグインクラス)だけが実行時のメソッドディスパッチを通る。
lambda-prelude run examples/01_hello.lp
lambda-prelude build examples/40_http_hello.lp --out hello-server
./hello-server設計原則
- 表層にパターンマッチを置かない。分岐は多態ディスパッチ。
- 値は不変。更新は新しい値を返す。
- 計算の唯一の形式はメッセージ送信。
- クラス継承を導入しない — プロトコル合成で共通化する。
- インスタンス変数を導入しない — 各オブジェクトは
fields:上の不変レコード。 - 共有可変状態を作らない — 可変性はアクター内部に閉じる。
- 完全推論の静的型システム。型注釈は任意。
- メタクラスも非ローカルリターンも導入しない。
- 本番実行は事前コンパイルされたネイティブバイナリ。
既存言語との違い
Q. 関数型 Smalltalk? Smalltalk-80 と何が違うの?
A. 主な違いは以下の通り。
- ソースファイルベース — 永続イメージではなく
.lpファイルでコードを管理する。Morphic も IDE 同梱環境も持たない。 - 静的型付き — 型注釈は任意。Hindley-Milner 推論が型を埋める。インタプリタは反復開発用、本番実行は事前コンパイル (AOT) されたネイティブバイナリ。
- 関数型 — オブジェクトは
fields:上の不変レコード、可変状態はアクター内部に閉じる。
イメージベースの Smalltalk が必要なら Squeak や Pharo を参照してほしい。
Q. アクターモデル? Erlang と何が違うの?
A. 主な違いは以下の通り。
- VM を持たない — AOT ネイティブバイナリとして実行する。BEAM のような管理ランタイムも、ホットコードロードも、分散プリミティブもない。
- アクターはノード内で完結 — 単一ノード内のアクターモデルはメッセージパッシングで構成する。
- 分散は別レイヤ — 複数ノード対応は 外部 KV を介した仮想アクター方式 で別個に扱う。
クラスタ形状のアクターが必要なら Erlang や Akka を参照してほしい。
Lambda Prelude は、Smalltalk の可読性を常駐バックエンドサービスの実行モデルに持ち込むためのものだ。
ライセンスとお問い合わせ
Lambda Prelude は プロプライエタリソフトウェアであり、すべての権利は 合同会社 Lambda に帰属します。Lambda Prelude の複製・改変・再配布には、合同会社 Lambda による書面での事前許可が必須 です。OSS ではありません。
バイナリ (lambda-prelude ランタイム、標準プラグイン、開発ツール一式) は 無償・無保証・現状有姿 (as-is) で提供します。評価・利用は すべてご自身の責任 で行ってください。特定用途への適合性は保証しません。別途契約しない限りサポートは提供せず、利用に起因する一切の損害について責任を負いません。
ソースコード は NDA を締結したパートナー企業にのみ開示します。この NDA および付随する個別契約が、ライセンス本文で要求される「書面での事前許可」にあたります。ソース開示は 有償案件 (共同開発・カスタマイズ・統合) とセット であり、ソース単体での販売は行いません。
製品開発や本番運用での Lambda Prelude 利用をご検討の場合は、お気軽にご相談ください。主に以下の 3 つの形態でご一緒します。
- 共同開発 — お客様のスタックに合わせたサービス、プロトコル、ドメイン特化拡張を貴社チームと共同で実装します。
- カスタマイズ — 独自プラグイン、チューニングビルド、独自プロトコル対応バインディングなど、運用環境に合わせた調整。
- NDA ベースのソース開示 — 社内拡張・監査・長期保守のためのフルソースアクセス。
ご相談は 合同会社 Lambda までお寄せください。