多言語統合解説¶
本章では、「機械学習から始めるプログラミング入門」の 14 言語(第 1 波の Python・Kotlin・TypeScript・F#、第 2 波の Java・C#・Scala・Go・Rust、第 3 波の Ruby・Clojure・Elixir・PHP・Haskell)で同じ 15 章を書いた結果を横断的に比べます。言語とライブラリの選び方、データの表し方、アルゴリズムの書き方、ライブラリとの突き合わせで見つかったこと、そしてどの版から読むとよいかを解説します。
本章の目的¶
各言語版では、その言語で機械学習のアルゴリズムを TDD で自作し、ライブラリに置き換えて結果を突き合わせることに集中しました。本章では視点を上げて、次の問いに答えます。
- 同じ題材・同じ手順で書いても、言語によって何が変わり、何が変わらないのか
- データの表し方(データフレーム・レコード・
Map)の違いは、コードとテストにどう表れたか - 型の強さ(動的型付けと型ヒント・漸進的な型付け・静的型付け・判別共用体)は、誤りをどこで見つけたか
- 機械学習のライブラリが成熟していない言語では、何を自作し、何を突き合わせられたか
- 乱数生成器そのものを自作すると、言語をまたいで数値を突き合わせられるのか
対象言語一覧¶
第 1 波
| 言語 | 実行環境 | テスト | 機械学習ライブラリ | API | Notebook |
|---|---|---|---|---|---|
| Python | CPython 3.12 | pytest | scikit-learn | FastAPI | JupyterLab |
| Kotlin | JVM(JDK 21) | kotlin.test + JUnit | Tribuo | Ktor | Kotlin Notebook |
| TypeScript | Node.js 22 | Vitest | ml.js 系 | Hono | なし |
| F# | .NET 10 | xUnit v3 | ML.NET・FSharp.Stats | Giraffe | Polyglot Notebooks |
第 2 波
| 言語 | 実行環境 | テスト | 機械学習ライブラリ | API | Notebook |
|---|---|---|---|---|---|
| Java | JVM(JDK 21) | JUnit 6 + AssertJ | Tribuo | Javalin | なし |
| C# | .NET 10 | xUnit v3 | ML.NET | ASP.NET Core Minimal API | なし |
| Scala | JVM(Scala 3.3 LTS) | ScalaTest | Tribuo | http4s + circe | なし |
| Go | Go 1.25 | 標準の testing(表駆動) |
gonum | 標準の net/http |
なし |
| Rust | Rust 1.91(edition 2024) | 標準の #[test] |
linfa | axum + tokio | なし |
第 3 波
| 言語 | 実行環境 | テスト | 機械学習ライブラリ | API | Notebook |
|---|---|---|---|---|---|
| Ruby | CRuby 3.3 | Minitest + SimpleCov | Rumale 2.2 | Sinatra + Puma | なし |
| Clojure | JVM(JDK 21) | clojure.test | Tribuo 4.3 | Ring + Jetty | なし |
| Elixir | BEAM(OTP 27) | ExUnit | Scholar 0.4 | Plug + Bandit | なし |
| PHP | PHP 8.4 | PHPUnit 11 | Rubix ML 2.6 | 標準の組み込みサーバー | なし |
| Haskell | GHC 9.10 | Hspec | 無し(線形代数の hmatrix のみ) | Scotty | なし |
Notebook を作ったのは第 1 波の 4 言語のうち Python・Kotlin・F# の 3 言語だけです。第 2 波・第 3 波の 10 言語は Notebook の節を設けず、Python 版・Kotlin 版の可視化の節へ案内しています。
番外編¶
14 言語のあとに、日本語で書くプログラミング言語 なでしこ3 の版を番外編として書きました(ADR 015)。
| 言語 | 実行環境 | テスト | 機械学習ライブラリ | API | Notebook |
|---|---|---|---|---|---|
| なでしこ3 | nadesiko3go 3.8.8(Go で書かれた処理系。コマンドは gonako) |
自作のテスト補助 | 無し(線形代数も自作) | JSON の標準入出力でやりとりするコマンド | なし |
なでしこ3 版は、本解説の 14 言語の表・レーダーチャート・総合スコアには含めません。理由は 2 つです。
- 比べる軸が違う。 日本語で書くこと(助詞が引数の役割を持ち、名前に使える語が文法と衝突する)と、1 回の実行につき 2 億命令という処理系の上限は、14 言語のどの軸にも当てはまりません
- 実データでの数値をまだ実測していない。 なでしこ3 版は学習データの無い環境で書き、数値は Python の参照実装と架空のデータで突き合わせました。14 言語と同じ表に数値を並べられる状態ではありません
なでしこ3 版をどう読むとよいかは、第 5 章 の「5.8 番外編: なでしこ3 版」にまとめました。
章構成¶
| 章 | タイトル | 内容 |
|---|---|---|
| 1 | 言語とライブラリの概要 | 14 言語の道具立て(実行環境・テスト・静的解析・ライブラリ・API・Notebook)と選定の理由 |
| 2 | データ構造の比較 | データフレーム・レコード・Map によるデータの表し方、欠損値、分割と乱数、言語によって数値が変わる理由と、そろえるために乱数生成器を自作した 3 言語 |
| 3 | アルゴリズムの実装の比較 | 決定木・評価と交差検証・エラーの表し方・API の層構成を 14 言語でどう書いたか |
| 4 | ライブラリのエコシステムの比較 | 章ごとのライブラリへの置き換えの可否と、突き合わせで見つかったライブラリの癖 |
| 5 | 学習ロードマップ | 目的別の読み方と、版をまたいだ読み進め方、14 言語の特性を 6 軸で比べるレーダーチャートと総合スコア、番外編(なでしこ3 版)の読み方 |
本章の数値について¶
本章に載せる数値と事実は、各言語版の記事・ADR 001〜014・apps/ の実装から取ったものです。本章のために新たに測った値はありません。
第 2 波までは「乱数生成器が違うので正解率などの数値は言語ごとに違う」と書いていましたが、第 3 波でこの前提が変わりました。Elixir・PHP・Haskell の 3 言語は java.util.Random と同じ線形合同法を自作したので、java.util.Random を使う 3 言語(Java・Scala・Clojure)と分割が一致し、第 3 章以降の数値が言語をまたいで突き合わせられるようになっています。詳しくは第 2 章で扱います。
表が横に広がりすぎる箇所は、波ごとに分けるか縦持ちに組み替えています。
番外編の節の事実は、なでしこ3 版の記事・ADR 015・apps/nadesiko3/ の実装から取りました。こちらも本章のために新たに測った値はありません。