クライアントとサーバの処理を別々のプロジェクトに分けて書き、通信プロトコルが噛み合うことを祈る——分散システムの面倒さの多くはここから来る。Wyzer(Wyzer-Lang/wyzer・★199)はこれを言語機能で解こうとする新しいプログラミング言語で、2026年8月7日のShow HNで217ポイントを集めた(本稿執筆時点。投稿直後は168ポイント前後だった)。

Wyzerで書かれた donut.wyz(3,208バイト)の実行映像。三角関数とzバッファで回転するトーラスを端末に描く定番プログラムを移植したもの。出典:rudywasfound/donut.wyz(MIT・作者本人によるスクリーンキャスト、2026-08-03収録)

30秒でわかるWyzer

何ができるかrole @Client; role @Server; と宣言し、1つのファイルに両者の処理を書く。コンパイラが --role 指定で各ノード向けにコードを削ぎ落とす(Endpoint Projection)
何を解決するか:送信と受信を別々に書くことで生まれるプロトコルの食い違い・デッドロックを、型検査の段階で潰す
何を代替するか:現時点では何も代替できない。リリース0本・コレクション型なし・複数ファイル非対応で、実務投入できる状態にない
実装の重心lib/typechecker.ml が79,029バイトで全体の3分の1を占め、ロール境界と線形性の検査が実装の中心にある

新しい言語を扱うワークフロー全体の位置づけについてはAI自動化ツール|ノーコードからコードまで2026年版の比較と選び方でツール側の選択肢を整理している。Wyzerが面白いのは、そこで語られる「複数システムのつなぎ込み」を、ツールではなく言語の型システム側に持ち込もうとしている点にある。

本稿は2026年8月10日時点のmasterブランチ(7f6acf0)を対象に、リポジトリのソース、同梱のCランタイム、GitHub API、公式サイトを突き合わせて書いている。OCamlツールチェーンでのコンパイラ本体のビルドは、LLVM OCamlバインディングの依存解決とディスク容量の都合で完遂できなかった。そのため以下では「ソースを読んで確認したこと」と「同梱ランタイムを直接実行して測ったこと」を区別して示す。

検証環境:macOS(Darwin 23.5.0・arm64)/ Apple clang(lib/wyzer_runtime.c の直接リンクに使用)/ GitHub REST API・Hacker News Algolia API / 検証日 2026-08-10(JST)。対象コミットは 7f6acf0

Wyzerとは——1つのファイルに複数ノードの処理を書く言語

Wyzerは静的型付け・リソース指向のコンパイル言語で、2つの研究成果を組み合わせている。

コレオグラフィック・プログラミング(Choreographic Programming)は、分散システム全体の振る舞いを1つの「振り付け」として記述し、そこから各参加者向けのコードを機械的に導出する手法だ。送信と受信を独立した2つの操作として書かないため、片方だけ書き忘れる・順序がずれるといった食い違いが原理的に起きにくい。

Perceusは、参照カウントを精密に配置することでGCなしにメモリを管理する方式で、Microsoft ResearchのKoka言語で実用化された。値の所有者が1つだけだと分かった時点で、新しい領域を確保せず既存のメモリをその場で書き換える(FBIP: Functional But In-Place)。

Wyzerリポジトリの概要。74コミットが12日間に集中、実装言語はOCaml、リリース0本、lib配下のソースサイズはtypechecker.mlが79029バイトで最大
GitHub APIとリポジトリ実体から集計(2026-08-10 JST時点)。作業量が型検査に集中しているのが数字で見て取れる。

RESEARCH.md(16,248バイト)はこの2つの出典を明示している。Perceusは Reinking, Xie, de Moura, Leijen による “Perceus: Garbage Free Reference Counting with Reuse”、コレオグラフィは Fabrizio Montesi の Introduction to Choreographies、さらに ECOOP 2021 の “Multiparty Languages: The Choreographic and Multitier Cases”(Giallorenzo, Montesi, Peressotti, Richter, Salvaneschi, Weisenburger)を挙げ、Wyzerを「多層プログラミングの書き味とコレオグラフィのコンパイル安全性を接続するもの」と位置づけている。思いつきではなく、既存研究を読んだ上での設計であることは文書から確認できる。

余談だが、Show HNのスレッドにはこの RESEARCH.md で引用されている Fabrizio Montesi 本人が現れ、コレオグラフィの基本概念とデッドロックが起きない理由を解説している。

リポジトリの実態

数字で見ると、この言語がどの段階にあるかがはっきりする。

★199 / fork 4 / watch 1(2026-08-10時点)
リリース・タグともに0本。バイナリ配布はなく、ソースからのビルドのみ
コミット74本すべてが2026-07-28〜08-08の12日間に収まる。リポジトリ自体は2025-04-13に作られている
・ただし最初のコミット(親なし・5ファイル・329行)のメッセージは “remove the old .git folder” で、それ以前の履歴は意図的に破棄されている。つまり「12日で書かれた」とは読めない。公開されている履歴が12日分しかない、というのが正確な言い方になる
・コミットの内訳は rudywasfound 49本+Atiksh Sharma 18本(同一人物のgit設定違い)、medhansh5 5本、他2名が各1本
.github/ ディレクトリが存在せず、CIは設定されていない
test/wyzer_test.ml の中身は let () = print_endline "Tests will go here" の1行で、自動テストは実質存在しない

履歴が破棄されている以上、開発に費やされた実時間は外からは分からない。確実に言えるのは、現在の形になったのは直近2週間ほどで、Show HN投稿はそのさなかだったということだ。以下で挙げる「未実装」は、放置された企画倒れの結果ではなく、動いているプロジェクトの現在地として読む必要がある。

インストールと最小のhello world——ビルドに必要なもの

Wyzerにはインストーラもバイナリ配布もない。OCamlのビルド環境を用意してソースからコンパイルする。

# 1. OCamlツールチェーン(opam)を用意する
brew install ocaml opam          # macOS。Linuxはディストリのパッケージか公式スクリプト
opam init --bare -y
opam switch create wyzer 5.2.0
eval $(opam env --switch=wyzer)

# 2. 依存を入れる。llvm は OCaml バインディングで、
#    システム側の LLVM 開発ライブラリ(>= 14)が別途必要になる
opam install -y dune menhir ppx_deriving llvm

# 3. ビルド
git clone https://github.com/Wyzer-Lang/wyzer.git
cd wyzer
dune build

lib/dune(libraries ppx_deriving.std unix llvm) が示すとおり、LLVMバインディングはインタプリタ実行にも必須だ。codegen.ml がライブラリに含まれている以上、コード生成を使わない run だけを試したい場合でもLLVMを解決しないとビルドが通らない。筆者の環境ではこの依存解決とディスク容量の制約でビルドを完遂できなかったため、以降のコンパイラ挙動に関する記述はソース読解に基づく。

書けるコードの最小形は素直だ。wyzer_tests/hello_world.wyz から引くと次のようになる。

import std::io;

fn main() {
    let x: u32 = 10;
    let y: u32 = 20;
    let sum: u32 = x + y;
    io::println(sum);

    io::println("Hello, Wyzer!");
}

型注釈にビット幅を明示する(u32 / i64 / f64)、let は不変で var が可変、といったRust寄りの構文になっている。Show HNでも「構文が保守的で読みやすい」という反応が複数あった。

実行は runbuild のサブコマンドを指定する。

# インタプリタで実行
dune exec wyzerc -- run wyzer_tests/hello_world.wyz

# LLVM経由でネイティブバイナリを生成(リポジトリ直下で実行すること)
dune exec wyzerc -- build wyzer_tests/hello_world.wyz --role Server

実際に書ける範囲

SPEC_SHEET.md(18,757バイト)の文法定義から、現時点で書ける要素を拾うと次のようになる。

基本型u8 / u16 / u32 / u64i8 / i16 / i32 / i64boolstrf64、ユーザー定義のenum・struct、Result<T, E>
変数let(不変)/ var(可変)/ const。代入は var で宣言したものだけに許される
制御構造if / elsewhilefor ... inmatch(網羅性検査つき)
ロール修飾base_type "@" role という形で、型に所属ノードを付けられる
文字列補間f"Value: {x}" 形式が実装済み

逆に、実務コードで真っ先に欲しくなるものが揃っていない。Vec<T>HashMap<K, V>TODO.md で未着手、スライス([u8])と太いポインタも未着手、Box / Rc / Arc のスマートポインタも未着手だ。ジェネリクスは実装されているがトレイト境界(generic<T: Show>)は未対応で、型クラス的な制約を書けない。複数ファイルへの分割もできないため、1ファイルに全部書くことになる。

この制約下でも donut.wyz が3,208バイトで成立しているのは、配列と std::collections::pushf64 の三角関数(std::math::sin / cos)がインタプリタ側で動くためだ。解決される std モジュールは io / fs / math / string / conv / collections / process / time / hw の9つに限られる。最後の hwstd::hw::bind_interrupt だけを持ち、中身は割り込み番号とハンドラ名を表示するスタブになっている。

もう一点、評価すべき部分がある。SPEC_SHEET.md は各節に [SETTLED](確定)/[DRAFT](暫定)/[OPEN](未解決) のマーカーを振り、「どこが固まっていてどこが未解決か」を明示している。冒頭で “Status: early draft.” と宣言した上でこの粒度を保っている仕様書は、この規模の個人プロジェクトでは珍しい。lib/parser.conflicts(2,273バイト)がリポジトリに含まれているのも同様で、menhirが報告する文法の衝突を隠さずコミットしている。

エラー表示も力が入っている。READMEに掲載されている診断出力の例では、移動済みの変数を再利用した際に次のような形式で表示されるとされている。

Error [E001]: use of moved variable `put_req`
╭─▶ example.wyz:31:22
│
│ 31 │     std::io::println(put_req);
│    │                      ╰────── variable `put_req` used here after being moved
│
├─▶ note: `put_req` is a linear resource and can only be used once
├─▶ help: consider passing it by reference if you need to use it multiple times
╰─────────────────────────────────────────────────

これはREADMEに掲載されている出力例であり、筆者が実行して得たものではない。ただし lib/diagnostic.ml(9,692バイト)と lib/error_codes.ml が行・列を持つスパンを保持して矢印つきの整形出力を組み立てているのは、ソース上で確認できる。TODO.md でも診断エンジン関連の3項目はすべてチェック済みになっている。

ドキュメント側のコマンドは現在の実装と食い違っている

docs/01_introduction.mddune exec wyzerc -- your_file.wyzCONTRIBUTING.mddune exec wyzerc wyzer_tests/io_test.wyz と書いているが、bin/main.mlSys.argv.(1)run または build を要求し、そうでなければ Unknown command: で終了する。ドキュメントどおりに叩くと動かない。またビルド時に実行される clang -O3 %s lib/wyzer_runtime.c -lm -o %slib/wyzer_runtime.c相対パスで参照するため、リポジトリ直下以外から実行すると失敗する。

Wyzerのrunとbuildは「別の言語」に近い——2つの実行経路

ここからが本題になる。bin/main.ml を読むと、Wyzerのコンパイルパイプラインは6段構成で、最後に大きく分岐する。

Wyzerのコンパイルパイプライン。型検査、コンパイル時評価、射影、Perceusを経て、runならインタプリタ、buildならLLVMコード生成に分岐する
bin/main.ml の process_file が実行する順序。--role を指定したときだけ Projection(EPP)が挟まる。
flowchart TD A["ソース .wyz"] --> B["Parser(menhir)"] B --> C["Typechecker:ロール境界と線形性"] C --> D["Comptime:コンパイル時評価"] D --> E{"--role の指定は?"} E -->|"あり"| F["Projection:他ロールを削除しsend/recvを注入"] E -->|"なし(既定 Poly)"| G["射影せず素通し"] F --> H["Perceus:drop挿入・再利用先の探索"] G --> H H --> I{"サブコマンド"} I -->|"run"| J["Eval:OCamlインタプリタで実行"] I -->|"build"| K["Codegen:LLVM IR → clang -O3"]

注目すべきは、この分岐の手前Perceus done. Starting LLVM codegen... という文字列が無条件に出力される点だ。run で実行してもこのメッセージは表示されるが、実際にはLLVMコード生成は行われずインタプリタに入る。ログを見て「コンパイルされた」と誤解しやすい箇所になっている。

そして重要なのは、この2つの経路で言語の意味論が変わることだ。

runとbuildで役割間通信の実装が異なることを示す比較図。buildは32bit整数のみで送受信の鍵が一致しない、runはMarshalで任意の値を運び鍵が一致する
同じソースでも、run と build では役割間通信とメモリ解放の実装が別系統になっている。

インタプリタ側(run)

lib/eval.ml の実装はこうなっている。

ETransfer (e, _) -> eval_expr env e ——transfer() は中の式を評価するだけで、ロール指定を捨てる。つまり run において transfer それ自体は何も送らない
・実際の受け渡しは、射影が注入する ENetSend / ENetRecv が担う。OCamlの Marshal でファイルに書き出すため、構造体でも文字列でも運べる
・ファイル名は送信側が /tmp/wyzer_ipc_<送信元>_<宛先>_<連番>、受信側が同じ規則で組み立てるので両側の鍵が一致する
・受信は0.1秒間隔のポーリングで待ち、読み終えたらファイルを削除する

コンパイル側(build)

lib/codegen.ml の宣言を見ると、運べるデータの幅が決まっている。

(* lib/codegen.ml *)
let ipc_send_type = function_type void_type [| str_type; i32_type |]
let ipc_recv_type = function_type i32_type [| str_type |]

送信は「文字列(宛先名)と i32 を受け取る」、受信は「i32 を返す」。つまりコンパイル経路でノード間を越えられるのは32ビット整数1個だけだ。READMEの看板例は str フィールドを2つ持つ KVRequest 構造体をノード間で移動させるが、この宣言のままでは通らない。

型検査側に制限はない。lib/typechecker.mlETransfer はロールが宣言済みかを確認して型に TRole を被せるだけで、運ぶ値の型は一切制約していない。制約が現れるのはコード生成の段階だけ、という構造になっている。

役割間通信の実体を測る——/tmpファイル・32ビット・タイムアウトなし

「ネットワーク転送」の実体を確かめるため、コンパイラ本体のビルドを待たずに、同梱の lib/wyzer_runtime.c(2,876バイト)を直接叩いて測った。このCファイルは build で生成したバイナリにリンクされる本物のランタイムなので、コンパイル経路の通信挙動をそのまま観察できる。

# 同梱ランタイムに小さなハーネスを噛ませて直接呼ぶ
cat > probe_send.c <<'EOF'
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
void wyzer_ipc_send(const char*, uint32_t);
int main(int argc, char** argv) {
  unsigned long long v = strtoull(argv[2], NULL, 10);
  wyzer_ipc_send(argv[1], (uint32_t)v);
  return 0;
}
EOF
cat > probe_recv.c <<'EOF'
#include <stdint.h>
#include <stdio.h>
uint32_t wyzer_ipc_recv(const char*);
int main(int argc, char** argv) { printf("received: %u\n", wyzer_ipc_recv(argv[1])); return 0; }
EOF
clang -O1 probe_send.c lib/wyzer_runtime.c -lm -o probe_send
clang -O1 probe_recv.c lib/wyzer_runtime.c -lm -o probe_recv

./probe_send Server 42
ls -l /tmp/wyzer_ipc_Server && cat /tmp/wyzer_ipc_Server

結果は次のとおりだった。

Cランタイムを直接呼んだ実測値。運べる幅は32ビット、socket呼び出しは0、ポーリング間隔は10ミリ秒、相手不在時の待機は無限
同梱 lib/wyzer_runtime.c をclangでリンクして直接実行した実測(2026-08-10)。

1. 転送先は /tmp の平文ファイル。 ./probe_send Server 42 を実行すると /tmp/wyzer_ipc_Server-rw-r--r-- の3バイトのASCIIテキストとして作られ、中身は 42 だった。同一マシンのユーザーなら誰でも読める。

2. 運べるのは32ビット整数1個。 4294967298(2^32 + 2)を渡すと、ディスク上には 2 が書かれ、受信側も 2 を受け取った。uint32_t で切り詰められている。

3. ソケットは1か所も使われていない。 lib/bin/ 全体に対して socket / connect / bind / listen / accept / tcp / udp / sockaddr を検索しても、ヒットするのは wyzer_ipc_sendwyzer_ipc_recv の関数定義行だけだった。READMEの言う「物理ノード(physical node)」は、現時点では同一マシン上の別プロセスを指す。

4. 受信は無限に待つ。 送信側が存在しない状態で受信を呼ぶと、10秒経過しても戻らず、エラーも出なかった。while(1) の中で10ミリ秒ずつ usleep するだけでタイムアウトがない。ただしCPU使用率は0.2%・RSS 928KBで、行儀の悪いビジーループではない。

送信と受信の鍵が噛み合っていない

さらに lib/projection.ml を読むと、コンパイル経路には別の問題がある。分岐の同期(Knowledge of Choice)で射影が生成するのは以下だ。

・判断する側(Client)には ENetSend("Server", ...) を注入する
・判断を受ける側(Server)には ENetRecv("Client") を注入する

一方Cランタイムは、送信では宛先名でファイル名を作り(/tmp/wyzer_ipc_<target>)、受信では送信元名でファイル名を作る(/tmp/wyzer_ipc_<src>)。したがってClientは /tmp/wyzer_ipc_Server に書き、Serverは /tmp/wyzer_ipc_Client を探すことになり、両者は永久にすれ違う。実測でも、送信後に受信側が探す名前のファイルは存在しなかった。

インタプリタ側は送受信とも <送信元>_<宛先>_<連番> で組み立てるため一致する。通信が成立するのは run の経路だけ、というのが現時点の姿だ。

これは作者の認識とも矛盾しない。TODO.md の「Choreography & Concurrency Enhancements」節にある “Compiler Backend: Export physical standalone binaries for projected nodes via C/OCaml code generation” は未チェックのままであり、std::net の節(TcpListenerTcpStream に「Foundational for choreographic roles」と注記されている)も全項目が未着手だ。バックエンドは本人が「これから」と書いている領域にあたる。

公式サイトのTCPサーバ例は現時点ではコンパイルできない

公式サイト(wyzer-lang.vercel.app)は std::net::TcpListener::bind("127.0.0.1:8080") を使うTCPサーバの例をトップページに掲載している。しかし eval.ml のディスパッチを端から拾うと、コンパイラが解決する std モジュールは io / fs / math / string / conv / collections / process / time / hw の9つで、net は含まれない。ソース全体を検索しても TcpListener / TcpStream / incoming は1か所も定義されていない。看板のコード例が実装に先行している状態にある。

WyzerのPerceusメモリモデルはどこまで動いているか

メモリ管理側も、通信と同じく「解析は動く/バックエンドが追いついていない」という構図になっている。

lib/perceus.ml(9,456バイト)が実装しているのは本物のPerceus解析だ。

・後ろ向きに走査して変数の生存区間を求め、使われなくなった地点に SDrop 文を挿入する
・構造体リテラルを作る際、直前に死んだ変数のメモリを再利用先として探すfind_candidate)。これがPerceusの肝であるFBIP(その場書き換え)の材料になる
EStruct / EOk / EErr の3種類で再利用先の探索を行う

インタプリタはこの結果を実際に使う。lib/eval.mlSDrop は参照カウントを1減らし、[Perceus] Drop 0x%X (refcount = %d) を出力し、0になればヒープから実際に解放して [Perceus] Freed 0x%X を出す。参照カウント方式が動作しているのを目視できる作りだ。

ところがLLVMバックエンドはこの成果を受け取らない。

(* lib/codegen.ml:536 — drop は何も生成しない *)
| SDrop _ -> ()

(* lib/codegen.ml:364 — 再利用先(第3要素)を _ で捨てている *)
| EStruct (_, fields, _) ->

codegen.ml 全体を malloc / free / 参照カウント関連の識別子で検索しても、該当するものが1つも無い。つまり解放処理が抜けているというより、LLVMバックエンドにはまだヒープ自体が無く、Perceusが管理する対象が出力されていない。リークしているのではなく、管理すべきものがまだ生成されていない段階にある。さらにPerceusのもう一方の柱である dup(参照カウントの増加)は、AST上に EDup として型は用意されているものの、perceus.ml はこれを一度も生成していない。挿入されるのは drop だけだ。

公式が掲げる姿とソースで確認できる範囲の対比。独立バイナリへの射影、C ABI互換、GCなしの解放がいずれもTODO未チェックまたはインタプリタ限定
README・公式サイトの記述と、TODO.md・lib/実装で確認できる範囲の対応関係。

READMEが設計原則として掲げる「C ABI compatibility」も、TODO.md では extern "C" ABI compatibility が未チェックの項目として並んでいる。

なお、Show HNではこの設計そのものに踏み込んだ指摘もあった。「線形型なら参照カウントは要らないはずで、Perceusを入れるということは値の共有を許すということ。『1つの所有ルール』はメモリではなくソケットや割り込みの層を説明しているのでは」という趣旨のコメントで、線形性と参照カウントの緊張関係を突いている。設計として詰め切られていない部分は残っている。

実装済みとされている領域

一方で、TODO.md がチェック済みとしている項目は実際にソースに対応物がある。

TODO.mdが済としている主な項目。EPP射影、網羅性検査、ADTとtrait、診断エンジンが実装済み、std::netは未着手
TODO.md のチェック状況から抜粋。フロントエンド寄りの項目は実装が進んでいる。

Endpoint Projection--role によるAST分割(projection.ml 11,485バイト)
パターンマッチの網羅性検査:集合の差分による判定(PR #3 / #4 で追加)
代数的データ型とtraitpub / priv の可視性修飾子
診断エンジン:行・列を持つスパンを保持し、Rustの rustc に似た矢印つきエラーを出す(diagnostic.ml 9,692バイト)

wyzer_tests/ には59本の .wyz ファイルが置かれ、choreo_fail.wyz(他ロールのグローバル変数を読もうとする)や match_non_exhaustive_fail.wyz のように「コンパイルが失敗すべきコード」も含まれている。ただしこれらは手で実行するサンプルで、期待結果を検証する仕組みはない。Show HNでも「コレオグラフィのテストが1〜2行しかなく、RESEARCH.mdが述べる内容を実証していない」という厳しい指摘が出ていた。本稿の計測はその指摘を実装レベルまで降ろして具体化したものになる。

他のコレオグラフィック言語・Perceus採用言語との比較

Wyzerの立ち位置を、同じ系譜のプロジェクトと並べて確認する。数値はいずれも2026-08-10にGitHub APIで取得した。

プロジェクト 形態 言語 ライセンス リリース 特徴
Wyzer 独立した言語 OCaml 199 表記が割れている 0本 コレオグラフィとPerceusの両方を1言語で持とうとする
Koka 独立した言語 Koka 4,011 NOASSERTION あり Perceusの発祥。効果ハンドラが中心で分散機能はない
Choral Javaへの拡張言語 Java 42 LGPL-2.1 あり Montesiらの研究実装。既存JVM資産をそのまま使える
ChoRus Rustライブラリ Rust 73 MIT あり 言語を作らずライブラリとして提供。2025-03が最終更新
HasChor Haskellライブラリ Haskell 129 BSD-3-Clause 0本 関数型言語への埋め込み実装
Electric Clojure Clojure方言 Clojure 2,134 明示なし 0本 多層プログラミング。フロント/バックを1式で書く

この表から見えるのは、コレオグラフィの実装には「既存言語にライブラリ/拡張として載せる」路線が主流だという点だ。Choral・ChoRus・HasChor・Electricはいずれも既存処理系に乗っており、ホスト言語のエコシステムをそのまま使える。Wyzerはこれを独立した言語として作り、さらにメモリモデルまで自前で持とうとしている。野心的だが、標準ライブラリもパッケージマネージャもゼロから作る必要があるという意味でもある。実際 TODO.md には Vec<T> / HashMap<K,V> / スライス / スマートポインタ / 複数ファイルコンパイル / パッケージマネージャがすべて未着手として並んでいる。

言語処理系を作る側の道具立てという点では、Go言語でLSP 3.17対応の言語サーバー開発が簡易化。go-lspライブラリ公開で扱ったLSPのような周辺ツールも実用化には効いてくるが、Wyzerには現時点でエディタ支援がない。既存言語を別のバックエンドに載せ替える方向の実装としてはTypeScriptをネイティブバイナリに変換するRust製コンパイラ「Perry」の仕組みとできることが対照的で、こちらは言語仕様を新造せず出力先だけを変える設計になっている。

新興プロジェクトの公称値をどう検証するかという観点では、Topcoatとは|tokio-rs発のフルスタックRust Webフレームワークの仕組みと使い方を解説でも同梱ベンチマークの数値が公開されていない例を扱った。看板の主張とリポジトリの実体を突き合わせる手順は、言語であれフレームワークであれ変わらない。

いまのWyzerをどう扱うか

読者の3つの問いへの答え

何ができるかrole 宣言と T@Role 型で、複数ノードにまたがる処理を1ファイルに書ける。--role を付けると他ロールのコードが削ぎ落とされ、分岐の同期メッセージが自動で挿入される。型検査は他ロールのデータへの直接アクセスを実際に弾く
何を解決するか:送信・受信の書き分けから生じる食い違いを、実行時ではなくコンパイル時に検出する。設計としてはこの一点に賭けている
何を代替するか:現時点では代替にならない。ネイティブバイナリ間の通信が成立せず、コレクション型も複数ファイルコンパイルもなく、リリースも配布物も存在しない

判断の材料を整理する。

触る価値がある場合:コレオグラフィック・プログラミングやPerceusを「動くコードとして」読みたい人には良い教材になる。projection.ml が11,485バイトでEndpoint Projectionの本体を読み切れる規模に収まっており、perceus.ml の生存解析と再利用先探索も9,456バイトで追える。論文を読む前の足がかりとして、実装の分量が手頃だ。

避けるべき場合:業務で分散システムを書く用途には現時点で使えない。上に挙げた通信の不整合に加え、Vec / HashMap が無いためデータ構造をほぼ組めず、複数ファイルに分割することもできない。

貢献を考える場合:リポジトリの AGENTS.md は、AIエージェントの用途をコミットメッセージの生成のみに制限し、コードの記述・バグ修正・ドキュメント生成を明示的に禁止している(CLAUDE.md は14バイトの Read AGENTS.md という転送用ファイル)。作者はShow HNでもこの方針を明言している。PRを送る際はこのポリシーを踏まえる必要がある。またCIが無いため、動作確認は手元で行うことになる。

最後にライセンスについて。リポジトリ内で表記が割れているLICENSE ファイルの本文はApache License 2.0で、GitHubのAPIも Apache-2.0 と認識している。一方 dune-project(license MIT) と、そこから自動生成される wyzer.opamlicense: "MIT" はMITを宣言している。Apache-2.0とMITでは特許条項の扱いが異なるため、コードを取り込む前に作者への確認が要る。

まとめると、Wyzerは設計の骨格と型検査は実在するが、バックエンドがまだ設計に追いついていない12日目のコンパイラだ。README・公式サイトが描く完成像を現在の能力と読むと確実に外す。逆に、コレオグラフィとPerceusを1つの言語に統合するとどういう実装になるのかを読むには、ちょうど良い分量と鮮度がある。

参照ソース

Wyzer-Lang/wyzer — GitHub(README.md / RESEARCH.md / TODO.md / SPEC_SHEET.md / CONTRIBUTING.md / AGENTS.md、および lib/ bin/ wyzer_tests/ の実ソース。master 7f6acf0、2026-08-10取得)
Show HN: Wyzer Programming Language — Hacker News(2026-08-07投稿。作者 v0id_isgood によるAGENTS.md方針の説明、Fabrizio Montesi によるコレオグラフィ解説を含む)
Wyzer Programming Language 公式サイト(トップページのコード例と機能説明、2026-08-10取得)
rudywasfound/donut.wyz — GitHub(MIT。冒頭のデモ映像の出典)
koka-lang/koka / choral-lang/choral / lsd-ucsc/ChoRus / gshen42/HasChor / hyperfiddle/electric(比較表の数値はGitHub APIで2026-08-10に取得)