OCaml Weekly News

先週号 上へ 次週号

こんにちは

2026年4月21日から28日までの週の OCaml Weekly News をお届けします。

Table of Contents

古いバグをテストで閉じる: Dune へのコントリビューション体験記

Robin Bate Boerop が発表しました

最近、コードベースに全く馴染みのない状態から Dune へのコントリビューションを始めました。やりがいを感じたのは、2018年まで遡るような古いイシューを閉じることで、その際に使ったアプローチを共有したいと思います。

方法: テストとともに閉じる

オープンなイシューの多くは、すでに修正済みの動作、あるいは正しく動いているのにテストで検証されていない動作を説明しています。私のアプローチは、期待される動作を示す cram テストを書き、fixes #NNNN でイシューに PR をリンクし、マージで自動的にイシューが閉じられるようにすることです。

これには、「これは今動いています」というコメントだけでイシューを閉じるよりもいくつかの利点があります:

  • 検証可能です。 テストを読めば、何の動作がアサートされているかが一目でわかります。イシューが本当に解決されているかどうかで議論になることがありません。
  • リグレッションを防ぎます。 将来その動作が壊れた場合、テストが失敗します。イシューが静かに再発することなく、CI が検知します。
  • テストスイートを充実させます。 閉じられたイシューのそれぞれが、誰かが気にかけていた実際のシナリオを文書化するテストを残します。
  • 報告者への敬意になります。 イシューを登録するために時間を割いてくれた人がいます。その懸念をとらえたテストは、ただ閉じるよりも適切な応答です。

数週間テスト PR とバグ修正をコントリビューションしたところ、プロジェクトのトリアージャーとなり、その後メンテナーの地位を与えられました。これにより、明らかに解決済みのイシューを直接閉じたり、自分のテスト PR をマージしたりできるようになりました。それ以前は、既存のメンテナーが代わりにマージしてくれていました。

正直なところ、この方法を使えたはずなのに使わずに閉じてしまったイシューは悔やまれます。この方法は、単にバグについての GitHub ディスカッションに追記してイシューを閉じるよりもはるかに優れています。

私がクローズに貢献したイシュー

私が貢献してクローズしたものを、何が必要だったかでグループ分けした一覧です:

  • 解決済みと確認し直接クローズ

    これらのイシューは、main 上ではすでに存在しない問題を説明していました。自分で確認したものもあれば、他の人がすでに検証していたものもあります。トリアージャー/メンテナーとしてクローズできました:

    • #1974@all ターゲットが (include_subdirs ...) とうまく連携しない (2019年登録)
    • #3173 — アンダースコアで始まるディレクトリへのプロモートができない (2020年登録)
    • #3805 — テスト中に DUNE_BUILD_DIR が設定されていると「そのようなファイルまたはディレクトリはありません」エラーが出る (2020年登録)
    • #8242 — emacs のコンパイルバッファの更新が非常に遅い (2023年登録)
    • #10360executables_implicit_empty_intf が dune >= 2.9 を期待しているが、実際には 3.0 で追加された (2024年登録)
  • テスト PR でクローズ

    これらのイシューは、正しい動作を示すテストを書くことで解決されました。コードの変更は不要で、テスト自体でイシューがクローズされました:

    • #2370 — foreign stubs なしで .h ファイルが _build にコピーされる (2019年登録、テスト: #14172)
    • #3362flags スタンザで %{lib:...} が使えない (2020年登録、テスト: #14146)
    • #3484 — 実行中のバイナリに対してプロモートする (2020年登録、テスト: #14173)
    • #11110 — Libexec サイトのインストールが実行ビットを設定しない (2024年登録、テスト: #14171)
  • テストとコード修正でクローズ

    これらはテストとコード変更の両方が必要でした:

    • #878dune subst が opam でバージョンフィールドを重複追加する (2018年登録、修正: #14136)
    • #2445 — dune が SIGTERM を先に送らず SIGKILL を送る (2019年登録、修正: #14170#14224)
    • #3916 — 自動生成された opam ファイルでバウンドが重複する (2020年登録、修正: #14175)
    • #6148root_module がモジュール定義を重複生成する (2022年登録、修正: #14135)
    • #9757dune runtest がバイトコードのみのインラインテストを実行しない (2024年登録、修正: #14174)
    • #10707 — 生成された opam ファイルに menhir の下限バウンドがない (2024年登録、修正: #14168)
    • #11002 — opam ファイル生成がエラーを起こしやすい (2024年登録、修正: #14136)
    • #11106 — opam ファイルに冗長な dune バージョン制約がある (2024年登録、修正: #14175)
    • #12007dune build @ocaml-index が多くのファイルをビルドしすぎる (2025年登録、部分修正: #14137)
    • #14089(wrapped (transition ...)) を使ったインクリメンタルビルドが壊れている (2026年登録、テスト: #14088、修正: #14090)

学んだこと

テストを書くことはコードベースを学ぶ良い方法です。 テストを書くたびに、機能が実際にどのように動作するかを理解することを強いられました。抽象的なアーキテクチャではなく、具体的なシナリオにおける実際の動作です。その理解は積み重なっていきます。

Dune の cram テストはこれを容易にします。 各テストは期待される出力を持つ自己完結したシェルスクリプトで、.t ファイルとしてリポジトリにチェックインされています。テストを書くための障壁は低く、イシューをテストでクローズするという目標には最適です。これが「あまりに簡単すぎる」ことで裏目に出ることも時々ありました。Dune らしいやり方でテストを書いていないとメンテナーに指摘されることがありましたが、それでもトータルでは確実にプラスでした。

継続的な存在感が重要です。 数週間にわたってほぼ毎日コントリビューションしました。これがメンテナーに私が「そこにいる」という感覚を与えたと思います。彼らが私を助けるために払った努力が投資になるため、レビューを渋ることが少なかったのだと思います。

ocaml-wire: EverParse 3D 出力付きのバイナリワイヤフォーマット DSL

Thomas Gazagnaire が発表しました

ocaml-wire 0.9.0 を opam にリリースできたことをお知らせします!

ocaml-wire は OCaml でバイナリプロトコルを記述するためのコンビネータのセットです。「バイナリ」とは固定レイアウトを意味します。サイズと形状はほとんど事前に分かっているため、自由形式の文法(Menhir のような)を解析するのではなく、既知のオフセットでフィールドを読み取ります。OCaml にはすでに優れたバイナリパーサフレームワークが多数あります。ocaml-wire の違いは次のとおりです:

  • 中心的なデータ構造は EverParse の 3D grammar です。OCaml のコンビネータは 3D 構造を記述します。Daniel の tagged final encoding アプローチに従い、構造体と OCaml 値からのシリアライズ/デシリアライズ方法を記述するコーデックを構築します。
  • つまり、すべての記述を .3d ファイルにコンパイルでき、そこから EverParse を通じて C にコンパイルできます。生成された C は -std=c99 -Wall -Werror でクリーンにコンパイルされます。理論上(まだそこまで追求していませんが)、メモリ安全性、シングルパスの動作、3D 仕様への準拠が F* で証明されたスタンドアロンの外部 C パーサーとして複雑なスタックをビルドおよびリンクすることができます(EverParse は残念ながらシリアライザを提供していません)。
  • OCaml のパーサー/ベリファイアを使いたい場合は、それも可能です。それらはホットパスで余分なアロケーションなしで合理的に高速化されており、ストリーミングコーデックなので構造体全体を解析せずに単一フィールドを読み書きできます。ブラウザで同じフォーマットを解析する必要がある場合、js_of_ocaml を通じて JavaScript にも簡単にコンパイルできます。

小さな例として、2 つのニブル幅フィールド、ビッグエンディアンの長さ、および Length フィールドから読み取った長さを持つ可変サイズのペイロードを含むパケット:

open Wire

type packet = { version : int; flags : int; length : int; payload : string }

let f_version = Field.v "Version" (bits ~width:4 U8)
let f_flags   = Field.v "Flags"   (bits ~width:4 U8)
let f_length  = Field.v "Length"  uint16be
let f_payload = Field.v "Payload" (byte_array ~size:(Field.ref f_length))

let codec =
  let open Codec in
  v "Packet" (fun version flags length payload -> { version; flags; length; payload })
    [ f_version $ (fun p -> p.version);
      f_flags   $ (fun p -> p.flags);
      f_length  $ (fun p -> p.length);
      f_payload $ (fun p -> p.payload) ]

Field.ref f_length が依存サイズの核心です。ペイロードの長さは同じ構造体内で以前に読み取られた f_length フィールドから取得されます。この同じコーデック値を Everparse.schema に渡すと 3D ファイルが出力され、OCaml からのストリーミングフィールドアクセスのために Codec.get / Codec.set のバックエンドにもなります。ocaml-wire には、FFI スタブを生成するためのインフラと、検証済み C と手書き OCaml パーサーが一致することを確認するための差分テストも含まれています。今のところ、それらは一致しているようです :-)

詳細はこちら: https://gazagnaire.org/blog/2026-03-31-ocaml-wire.html

試すには: opam install wire

イシュートラッカー(またはこちら)でのフィードバックを歓迎します!

valkey: OCaml 5 + Eio 向けモダン Valkey クライアント、opam で公開

Avi Fenesh が発表しました

こんにちは、

valkey 0.2.0 が opam で公開されたことをお知らせしたいと思います:

このプロジェクトで主に実現したかったのは、最新の Valkey スタックと新しい OCaml スタックに焦点を当てることでした。

valkey は以下を基盤としています:

  • OCaml 5
  • Eio ネイティブのダイレクトスタイル並行処理
  • RESP3 のみ
  • モダンな Valkey 機能と実際のクラスター動作

気に入っている点をいくつか挙げます:

  • 耐久性と高可用性に強く焦点を当てたクラスターサポート: トポロジーリフレッシュ、定期的なバックグラウンドリフレッシュ、MOVED / ASK / CLUSTERDOWN ハンドリング、レプリカ対応のリード、AZ 対応のルーティング、フェイルオーバー対応のシャードパブサブリプレイ
  • 接続/ランタイムの動作: サーキットブレーカー、再接続ハンドリング、キープアライブ、TLS、Eio.Domain_manager によるソケット I/O と解析の分離(オプション)、片方がもう一方をブロックしないようにします
  • バッチサポート: スロット間のスキャッタギャザー、WATCH / MULTI / EXEC によるアトミックなシングルスロットフロー、マルチスロットヘルパー、0.2.0 では読み取り-変更-書き込み CAS 用の WATCH ガードとクロススロットの pfcount_cluster も追加
  • コマンドサーフェス: 幅広いコマンドセットにわたる型付きヘルパー、カスタムコマンドとマルチノード実行のための Client.custom / custom_multi、一度登録して後で再利用できる名前付きコマンド
  • スクリプティング: ローカルスクリプトキャッシングと楽観的な EVALSHA ハンドリング(NOSCRIPT での自動フォールバック/リトライ付き)、呼び出し元がそのフローを自分で管理する必要がありません

また、周辺にはかなり充実した検証も既にあります: インテグレーションテスト、プロパティテスト、ファジング、カオステスト、例、ガイド。

パフォーマンス面でも良い結果が出ています:いくつかのシナリオでは C リファレンスクライアントの 90% 以上に達しています。

opam update
opam install valkey eio_main

ロードマップの次のステップには以下のようなものがあります:

  • クライアントサイドキャッシング
  • コネクションプール / ブロッキングプール
  • IAM + mTLS
  • Valkey モジュールサポート(JSON、サーチ、ブルーム)

皆さんが気にかけている機能があれば、実際の関心に合わせてロードマップの優先順位を変えることを喜んでします。

API、エルゴノミクス、ドキュメント、全体的な設計についても OCaml コミュニティからのフィードバックをぜひいただきたいと思っています。

Valkey の世界は熟知していますが、OCaml は日常の言語というよりは楽しみのサイドプロジェクトに近いので、OCaml エコシステムで本当に生きている人々からのフィードバックは特に貴重です。

試していただけたら、ぜひご感想をお聞かせください。

UnifiedScript_{Std,Top} - リテレートテスティング

jbeckford が発表しました

UnifiedScript_StdUnifiedScript_Top パッケージをご紹介できることを嬉しく思います。Unified script はテストとドキュメントを同時に書く方法です。Cram テストと MDX スクリプトはどちらも unified script に似ていますが、unified script は Markdown(MDX)にも POSIX シェルコマンド(cram テスト)にも縛られていません。

例:

  • Markdown の例: ocaml-re から変換した多数のテストが Markdown で書かれています: ocaml-re/EXAMPLES.md。多くのテストが Markdown テーブルとして表示されるよう、カスタム OCaml REPL プリンターが使用されています。余談: すでに書いているテストがドキュメントになったらいいと思いませんか?これは https://discuss.ocaml.org/t/what-are-the-biggest-reasons-newcomers-give-up-on-ocaml/10958/13?u=jbeckford/ への 4 年後のフォローアップです
  • .ml の例: 以下は 通常の OCaml .ml モジュール のスニペットで、(* ... *) コメントは unified ツールによって管理された OCaml REPL トップレベルの応答です。

    let lyrics =
      "Everybody step to the left."
      (* val lyrics : string = "Everybody step to the left." *)[@ocamlformat "disable"]
    
    let (_ : string) =
      Printf.sprintf "Now let's sing: %s" lyrics
      (* - : string = "Now let's sing: Everybody step to the left." *)[@ocamlformat "disable"]
    

ドキュメントは dk/docs/UNIFIED_SCRIPTS.md(もちろん unified ツールで生成されています)にあります。

ツールは以下でインストールできます:

opam pin add UnifiedScript_Std https://gitlab.com/dkml/build-tools/MlFront/-/releases/permalink/latest/downloads/MlFront.tar.gz
opam pin add UnifiedScript_Top https://gitlab.com/dkml/build-tools/MlFront/-/releases/permalink/latest/downloads/MlFront.tar.gz

フィードバックをいただいた後、opam へ正式にリリースする予定です。全般的なフィードバックと、特に expect テストを unified テストに変換するエージェントスキルについてのフィードバックをお待ちしています。

openrouter_api: OpenRouter クライアントライブラリ

mt_caret が発表しました

openrouter_api の最初のバージョン(v0.0.1)を発表できることを嬉しく思います。これは、統一された API の下でさまざまなモデルへのアクセスを提供するサービスである OpenRouter を通じて大規模言語モデルにクエリを送るためのライブラリです。

AI モデルを統合したいときに個人プロジェクトでこのライブラリを使ってきましたが、とても役に立っています。他の方々にも役立つことを願っています。イシューやコントリビューションを歓迎します。

発表募集: Caml in the Capital II

このスレッドを続けて、Sacha Ayoun が発表しました

日時と場所が確定しました!6月3日に Jane Street オフィスで開催します! 投稿を更新しました。

発表のプロポーザルも引き続き受け付けています!

過去の CWN

CWN を見逃した場合は、メッセージを送っていただければメールでお送りします。また、アーカイブRSS フィードもご覧いただけます。

毎週メールで受け取りたい場合は、caml-list を購読してください。