asopi techOSS Developer
asopi tech
asopi techOSS Developer
「Roc」入門 — Elm譲りの純粋関数型言語がRustホストと組む未来

【2026年7月版】

「Roc」入門 — Elm譲りの純粋関数型言語がRustホストと組む未来

公開日: 2026/07/03
読了時間: 約 13分

はじめに

こんにちは、あそぴテックです。

前回の記事「「Nim」入門 — Cにトランスパイルするマルチパラダイム言語の現在地」では、AlopexDB の SQL パーサー移行候補として調査された Nim を紹介しました。今回は、その調査でもう一方の主役だった Roc(ロック) を取り上げます。

Roc は Elm の作者 Richard Feldman 氏が率いる、比較的新しい純粋関数型言語です。「Rust ホスト + Roc アプリケーション」という独特のアーキテクチャで、システム系の世界に関数型を持ち込もうとしています。

Roc ってどんな言語?

Roc は次のような特徴を持ちます。

  • 純粋関数型 — 副作用は明示的、参照透過性が保たれる
  • Hindley-Milner 型推論 — 型注釈をほとんど書かずに強い静的型付けが得られる
  • ADT + パターンマッチが第一級 — Tag Union([Ok val, Err e] のような直和型)が言語の中心
  • Perceus 参照カウント — GC はあるが停止時間なし・スケジューリング不要を目指す設計
  • LLVM ネイティブへコンパイル — ネイティブバイナリを吐く
  • Platform / Host モデル — システムコールや副作用は「Platform」に集約し、アプリは純粋関数として書く

言語仕様の雰囲気は Elm や Haskell にかなり近く、初見でもかなり読みやすいです。次のコードは Roc の SQL レキサー実装の一部です(alopex-db/alopex experiment/sql-parser-trial より抜粋)。

Token : [Select, From, Where, Ident Str, IntLit I64, Star, Comma, Eq]

keyword : Str, Token -> Parser Utf8 Token
keyword = |text, tag|
    const(tag) |> skip(string(text))

token : Parser Utf8 Token
token = one_of([
    keyword("SELECT", Select),
    keyword("FROM", From),
    string("*") |> map(|_| Star),
    string(",") |> map(|_| Comma),
    many1(alpha) |> map(|chars| Ident(Str.from_utf8(chars))),
])

「関数を演算子でつないでいく」パイプライン |> と、パターン一致でトークンを組み立てる書き方は、Elm や F# を触ったことがある人なら違和感がないはずです。

2026年6月時点の現在地 — 「まだ 0.1 でもない」段階

Roc は 本当に若い言語 です。2026 年 6 月時点で見ると、以下のようなステータスになっています。

バージョン変遷

リリース日付備考
alpha12025-01-29初の alpha リリース
alpha2-rolling2025-01-29大規模構文変更
alpha3-rolling2025-02-26
alpha4-rolling2025-08-26最新版。ビルド速度改善、新 builtins

公式は明確に 「Roc is not ready for a 0.1 release yet」 と述べており、1.0 のタイムラインも未発表です。

alpha2 での破壊的変更(2025年1月)

alpha2 では、言語設計の見直しに伴う大規模な破壊的変更が入りました。

変更BeforeAfter
関数呼び出しfunc argfunc(arg)
命名規則camelCasesnake_case
エラーハンドリングTask! サフィックス + ? 演算子
文字列補間$(expr)${expr}
論理演算子&& / ||and / or
タグ構築Ok valOk(val)

移行ツール roc format --migrate は提供されていますが、Task! の置き換えは手動対応が必要でした。実際に Alopex チームが SQL パーサー試験実装で計測したところ、24 箇所の手動修正 が発生しています。

alpha 段階の言語である以上、この規模の破壊的変更は今後も想定しておく必要があります。

Zig コンパイラへの書き直し

大きな話題として、Roc コンパイラの LLVM コード生成部分が Rust(約 18,000 行)から Zig(約 1,700 行)に書き直されました。

項目内容
規模18,000 行 Rust → 1,700 行 Zig(10 倍削減)
アーキテクチャMono IR → Canonical IR(プレ単相化)に変更
未実装機能match 式、ラムダ、複雑な union、参照カウント、デバッグ情報
優先課題builtins 実装の完了(Issue #9596)

Rust 版で膨らみすぎたコンパイラを、Zig の comptime を活かして根本から作り直しているというかなり大胆な判断です。ちなみに Roc の「Host(副作用担当)」は引き続き Rust で書けますし、basic-webserver は Rust の hyper + tokio がホストになっています。「コンパイラ自体を書く言語」と「アプリの Host を書く言語」を分けて考えている のは Roc らしい選択と言えるでしょう。

コミュニティ

  • GitHub 5,700 stars / 387 forks / 43,653 commits
  • Zulip チャットが活発
  • コードベースの 92.9% が Zig

Roc のここが面白い

純粋関数型 + ADT ファースト

Roc の AST は、Elm と同じく Tag Union で自然に書けます。

Ast.roc
SqlNode : [
    Ident Str,
    StrLit Str,
    IntLit I64,
    BoolLit Bool,
    NullLit,
    StarLit,
    BinOp { op : BinaryOp, left : SqlNode, right : SqlNode },
    UnOp { op : UnaryOp, operand : SqlNode },
    FnCall { name : Str, args : List SqlNode },
    ColRef { table : Str, column : Str },
    SelectStmt {
        columns : List SqlNode,
        from : List SqlNode,
        where : [Some SqlNode, None],
        # ...
    },
    InsertStmt { table : Str, columns : List Str, values : List SqlNode },
    # ...
]

Rust であれば Box<SqlNode> を使い、enum の variant サイズが揃わずに #[allow(clippy::large_enum_variant)] を書きたくなるところですが、Roc は Box の概念がユーザーコードに現れません。ランタイムが自動的にヒープに載せ、Perceus 参照カウントで管理します。

Perceus 参照カウント

Roc の GC 戦略は Perceus と呼ばれる方式で、Koka 言語の研究成果を取り入れたものです。特徴は次の通りです。

  • 静的解析でカウント操作の位置を決定 → 実行時のアトミック操作を最小化
  • stop-the-world がない
  • 手動チューニング不要
  • 将来的にリニア型による “in-place update” 最適化も見据えている

Platform / Host モデル

Roc で最も特徴的なのは Platform / Host モデル です。副作用(ファイル IO、HTTP、TCP など)はすべて Platform が提供し、アプリ側(Roc コード)は「純粋関数の集合」として書きます。

代表的な Platform を挙げます。

Platformバージョン概要
basic-cliv0.20.0 (2025-08)ファイル、HTTP、TCP、CLI 引数
basic-webserverv0.13.1 (2026-01)Rust (hyper + tokio) バックエンドの Web サーバ

つまり Rust で書かれた Host が、内部で Roc アプリを C ABI 経由で呼び出す 形で動作します。

Roc App (純粋関数)
    ↓ C ABI で export(roc_app_main 等)
Rust Host (副作用担当)

OS / Network / DB

これは、後述する AlopexDB の「Rust ストレージエンジン + Roc パーサー」 構成と非常に相性が良く、「言語横断でクリーンに責任を分離できる」設計です。

コンテナ開発環境

Roc は現時点で公式 Docker イメージを提供していませんが、バイナリリリースを curl + tar で入れれば完結します。

Dockerfile
FROM debian:bookworm-slim AS roc-env

RUN apt-get update && apt-get install -y \
    curl ca-certificates gcc libc6-dev \
  && rm -rf /var/lib/apt/lists/*

ARG ROC_VERSION=alpha4-rolling
RUN curl -OL https://github.com/roc-lang/roc/releases/download/${ROC_VERSION}/roc-linux_x86_64-${ROC_VERSION}.tar.gz \
  && tar xzf roc-linux_x86_64-${ROC_VERSION}.tar.gz \
  && mv roc-linux_x86_64-${ROC_VERSION} /opt/roc \
  && rm roc-linux_x86_64-${ROC_VERSION}.tar.gz

ENV PATH="/opt/roc:${PATH}"
WORKDIR /app

Nix Flake での再現性重視なセットアップも可能です。

flake.nix
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    roc.url = "github:roc-lang/roc";
  };

  outputs = { nixpkgs, roc, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
      rocPkgs = roc.packages.${system};
    in {
      devShells.${system}.default = pkgs.mkShell {
        buildInputs = [ rocPkgs.cli ];
      };
    };
}

バイナリの取得さえ通れば構築コストは Nim とほぼ同等 です。差は「公式イメージがあるか」だけであって、コンテナ内では curl + tar で完了します。

ランタイム性能 — データは未公開

正直に書くと、Roc の対 Rust ベンチマークは公開データがまだ揃っていません。公式は「GC 付き主要言語(Go, C#, Java, JS)より速い」を目標に掲げていますが、Rust や Nim との定量比較は現時点で存在しません。

一方で、コード量とビルド時間についてはかなり良い数字が出ています(Alopex での試験実装、SQL パーサー現在の実装コード量)。

計測項目RocRust
実装コード量1,049 行2,964 行
release ビルド4.7 秒165 秒
dev ビルド0.8 秒
テスト実行のみ0.3 秒0.01 秒
SQLite 相当推定(dev)〜5 秒
SQLite 相当推定(テスト実行)〜2 秒

release ビルドは Nim よりやや遅いのですが、dev ビルド 0.8 秒 → SQLite 相当でも 5 秒程度 という開発イテレーションの速さが Roc の大きな武器です。

Roc で運用する場合の注意点

以下は Alopex の試験実装で実際に踏んだ落とし穴です。

  • --linker=legacy が必須(Linux) — surgical linker の issue #3609 が未解決
  • basic-cli の URL ハッシュが版ごとに変わる — Dockerfile のメンテコストになる
  • 未使用 import はコンパイルエラー(exit code 2) — 修正必須
  • .roc ファイルの命名規則がやや厳しい — CamelCase モジュール名との整合など
  • API 変更の頻度が高い — 上記の 24 箇所修正はその典型

言語設計は洗練されていますが、本番採用には時期尚早 というのが現状の総合評価です。まずは PoC / 実験ブランチで先行評価する、というのが妥当な向き合い方でしょう。

Roc は「今」誰にとって魅力的か

Roc を触ってみる価値があるのは、次のような層だと感じます。

  • Elm や Haskell 経験者で、システム系寄りに関数型を持ち込みたい人
  • AST 定義・パーサー・純粋計算コアを、GC ありつつも安全に書きたい人
  • Rust ホスト + 関数型アプリ という新しい構成に興味がある人
  • 言語処理系そのものの設計(Perceus、Platform/Host、Canonical IR)を追いかけたい人

逆に、「今すぐ本番サービスを構築したい」「ライブラリエコシステムがある程度揃っていてほしい」場合は、まだ Nim・Rust・Go を選んでおいた方が確実です。

とはいえ、Zig コンパイラ書き直しが完了して 0.1 → 1.0 のロードマップが見えてきたら、「純粋関数型 × ネイティブ性能 × Rust 連携」の三拍子が揃った稀有な言語になるはずで、今のうちから追いかけておく価値は十分にある と個人的には感じています。

次回は、この Nim と Roc それぞれで実装された SQL パーサーの中身を並べて比較する 記事を書きます。次の記事「Rustは万能じゃない — 言語パーサーはNimかRocで書け」で、同じ機能を 3 言語で書くと何が見えてくるのかを解説しています。

それでは!

参考リンク