Perl の既存システムを保守しながら Claude Code などの AI コーディングエージェントを使い始めると、「AI は Python や TypeScript ばかり得意で、Perl では古い記法や構文エラーで試行錯誤が増え、時間やトークンの面で割を食うのではないか」という懸念にぶつかります。AI コーディングの効率を高めるために、いっそ TypeScript 等へ全面リプレイスすべきか迷っている現場も少なくありません。

AI コーディングにおける Perl の効率特性とは、ゼロから実装を立ち上げる新規作成(v1)では言語固有の数値仕様や編集ツールの罠で試行錯誤が増えやすい一方、既存のコードベースに機能を追加する拡張(v2)では Ruby・Python・JavaScript のトップ3に迫る速さと安定性を発揮するという非対称な構造のことです。

2026年3月に遠藤侑介氏(@mametter)が公開し InfoQ でも報じられた「13言語・15条件×20試行=600回の Claude Code ベンチマーク」では、Ruby・Python・JavaScript が総合時間の上位を占め、Perl は15条件中7位(平均 130.2s±44.2s、平均コスト $0.55)でした123。しかし総合順位だけを見て「Perl は AI に向かない」と結論づけるのは早計です。フェーズ別の内訳と、公開リポジトリ(mame/ai-coding-lang-bench)の手順に沿って2026年10月に手元で実施した追試ログ(一次検証ログ)を突き合わせると、ゼロからの立ち上げ(v1)と既存コードの機能拡張(v2)でまったく異なる景色が見えてきます。

既刊の プログラミング言語別のトークン効率を検証した記事 では TypeScript・Python・Bash の3言語で新規実装時のトークン消費を比較し、Perl 製 EC サイトの段階的モダナイゼーションを解説した記事 では全面リプレイスに踏み切る前の環境整備を扱いましたが、本記事では公開ベンチマークの SPEC-v1.txt / SPEC-v2.txt を用いた Perl の実測追試データから、どこでターン数が跳ね上がり、なぜ既存コードの拡張ではトップ層並みに速いのかを解明します。

検証環境と調査スコープ ── 公開ベンチマークと手元追試の条件

本記事では、2026年3月5日に公開された元ベンチマーク(600回試行)のデータ14と、2026年10月16日に手元で実施した Perl 単体の追試ログ(3試行・計6実行の一次検証ログ)の2つを分析対象とします。それぞれの実行環境は以下のとおりです。

  • 元ベンチマークの計測環境(2026年3月公開)14
    • Claude Code バージョン: 2.1.68 (Claude Code)(モデル: Claude Opus 4.6、high effort)
    • Perl バージョン: This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi
    • 試行回数: 13言語・15条件 × 各20試行(v1・v2 の2フェーズ合計600実行)
  • 手元での追試環境(2026年10月16日実施・一次検証ログ)
    • 計測日時: 2026-10-16T01:43:13Z 〜 2026-10-16T01:46:41Z
    • Claude Code バージョン: 2.1.301 (Claude Code)
    • モデル: claude-opus-5-5
    • Perl バージョン: This is perl 5, version 42, subversion 2 (v5.42.2) built for darwin-2level
    • 実行コマンド: ruby benchmark.rb --lang perl --trials 3(Perl 1言語のみ3試行、v1・v2 計6実行)

手元の追試は Perl 1言語のみ(3試行)であり、モデルの世代(Claude Opus 4.6 と Claude Opus 5.5)や CLI バージョン、試行回数(20試行と3試行)が元ベンチマークとは異なります。したがって、追試データから「他言語に対する Perl の相対順位が上がった/下がった」と主張することはせず、「Perl 内部における v1(新規作成)と v2(機能拡張)の非対称性が半年後の環境でも再現されるか」および「v1 でターン数を消費した具体的な原因は何か」を観察スコープとします。

評価基準とタスク仕様 ── v1(新規作成)と v2(機能拡張)は何が違うか

mame/ai-coding-lang-bench のベンチマークは、外部ライブラリ禁止(External libraries: NOT allowed)・標準ライブラリのみ許可(Standard library: Allowed)という制約下で、簡易版 Git である実行ファイル minigit を実装させる2段階のタスクで構成されています567。

  1. Phase 1(v1: ゼロからの新規作成): 空のディレクトリからスタートし、minigit init、minigit add <file>、minigit commit -m "<message>"、minigit log の4コマンドと、64bit符号なし整数演算を用いた独自ハッシュ関数 MiniHash を実装して test-v1.sh(全11テスト項目)を通過させます56。
  2. Phase 2(v2: 既存コードへの機能拡張): v1 で生成されたディレクトリをそのままコピー(FileUtils.cp_r(v1_dir, v2_dir))した状態からスタートし、minigit status、minigit diff <commit1> <commit2>、minigit checkout <commit_hash>、minigit reset <commit_hash>、minigit rm <file>、minigit show <commit_hash> の6コマンドを追加して test-v2.sh(全30テスト項目)を通過させます678。

benchmark.rb は各フェーズで claude -p を実行し、モデルが応答を返した API ラウンドトリップ数(num_turns)、入出力およびキャッシュトークン数、所要時間、そして空行を除いたコード行数(File.readlines(f).count { |l| !l.strip.empty? })を集計します8。

私自身は、AI コーディングのコストや速度を比較する際、料金改定やベースシステムプロンプトのサイズ変更で陳腐化するドル換算金額ではなく、ターン数(API 往復回数)・トークン数(特にリトライのたびに過去の会話履歴プレフィックスが累積する cache_read_input_tokens)・所要時間 を主軸に据えて評価しています。

Claude API の自動プロンプトキャッシュ(Prompt Caching)では、マルチターン会話において tools → system → messages の順でプレフィックスがキャッシュされ、ツール実行やテスト失敗でターン数が増えるほど過去のコンテキスト全体を読み直す cache_read_input_tokens が累積します9。また、Claude Opus 4.6(Base Input $5 / MTok、5m Cache Writes $6.25 / MTok、1h Cache Writes $10 / MTok、Cache Hits $0.50 / MTok、Output $25 / MTok)と Claude Opus 5.5(Base Input $4 / MTok、5m Cache Writes $5 / MTok、1h Cache Writes $8 / MTok、Cache Hits $0.20 / MTok、Output $20 / MTok)ではトークン単価自体が改定されている上、CLI バージョン間のキャッシュ TTL 設定(5m / 1h)やシステムプロンプト長の違いで初回キャッシュ書込み量(cache_creation_input_tokens)も変動します9。だからこそ、試行錯誤の有無を直接反映するターン数と cache_read トークン内訳を見る必要があります。

13言語ベンチマーク(600回試行)に見る Perl の非対称性 ── 新規作成は13位、機能拡張は4位

まず、遠藤侑介氏が公開した600回試行ベンチマークのレポート(results/report.md および解説記事)から、上位3言語と Perl のフェーズ別データを比較します124。

元ベンチマークの主要4言語(Ruby・Python・JavaScript・Perl)を比較すると、Perl はゼロからの新規作成(v1)では 84.4s±43.1s と上位3言語の約2.5倍の時間を要して15条件中13位に沈んでいますが、既存コードを拡張する v2 では 45.7s±6.8s となり、3位 JavaScript(45.1s)とわずか0.6秒差の全体4位に付けています。

言語(条件)v1 時間 (s)v1 ターン数v2 時間 (s)v2 ターン数合計時間 (s)平均 Cache Read最終 LOC平均コストテスト合格
Ruby33.2s±2.5s6.040.0s±3.0s7.073.1s±4.2s253,371219$0.3640/40
Python32.9s±1.3s6.041.8s±4.5s7.174.6s±4.5s262,243235$0.3840/40
JavaScript36.0s±3.5s6.045.1s±4.1s7.381.1s±5.0s264,579248$0.3940/40
Perl84.4s±43.1s9.3 (9.2)45.7s±6.8s7.5130.2s±44.2s371,364315$0.5540/40

つまり Perl が総合7位($0.55)に落ちた差の大半は v1(新規作成フェーズ)の試行錯誤にあり、土台となるコードが存在する v2(機能拡張フェーズ)に限れば、静的型検査付きの Typescript(v2 63.1s±17.8s、総合 133.0s)や Python/mypy(v2 72.6s±14.4s、総合 125.3s)、Ruby/steep(v2 81.6s±8.8s、総合 186.6s)を大きく引き離して動的スクリプト言語トップ層と並走しています14。

(※注: Perl の v1 平均ターン数は20試行の合計185ターン÷20=9.25のため、results/report.md では四捨五入の 9.3、Zenn・DEV Community 記事では切り捨ての 9.2 と記載されています124。)

results/report.md に記録された Perl 全20試行の個別データ(Full Results / Full Tokens)を掘り下げると、この非対称性はさらに鮮明になります4。

  • v1(新規作成)の激しいばらつき: 最速だった Trial 8 は 42.5s(6ターン、LOC 183、Cache Read 119,997、v1 コスト $0.1790)で完了している一方、最遅の Trial 12 は 228.7s(20ターン、LOC 162、Output 12,670、Cache Read 606,244、v1 コスト $0.7816)まで膨らんでおり、20回中8回で10ターン以上を要していました4。
  • v2(機能拡張)の極めて高い安定性: 同じ20試行の v2 を見ると、全20試行すべてが6〜9ターン(最短 Trial 4 の 37.0s/6ターン〜最長 Trial 3 の 68.8s/9ターン) の狭いレンジに収まっています。v1 で20ターン(228.7s)かかった Trial 12 でさえ、v2 は8ターン・42.1s(Output 2,419、Cache Read 171,997、v2 コスト $0.2438)でスムーズに完了していました4。

もちろん、この数値は遠藤侑介氏による単一のベンチマーク実験(外部ライブラリを使わない約200行規模(InfoQ の表現)の minigit 実装課題)に基づくものであり、InfoQ が報じたコミュニティ議論でも指摘されているとおり、大規模システムの長期保守性そのものを直接測ったものではありません13。しかし「ゼロから書くときに特定の罠でリトライが多発し、既存の構造に乗せる機能拡張ではトップ層並みに速い」という傾向がなぜ生じるのかは、手元で追試してセッショントランスクリプトを覗くことで具体的に特定できます。

手元での追試結果と実行ログ解剖 ── なぜ v1 で12ターンかかり、v2 は4ターンで通ったのか

2026年10月16日、公開リポジトリと同じ ruby benchmark.rb --lang perl --trials 3 を Claude Code 2.1.301(claude-opus-5-5)・Perl v5.42.2 の環境で実行し、全6セッションのツール呼び出しとエラー出力を一次検証ログとして記録しました。

3試行(計6実行)の計測結果と元ベンチとの比較

手元で実施した Perl 3試行の追試でも、v1(新規作成)は 29.3s〜60.5s(3〜12ターン、平均 41.1±16.9s)とばらついたのに対し、v2(機能拡張)は全3試行が 25.4s〜31.1s(4〜5ターン、平均 27.4±3.2s)で一発通過し、元ベンチマークで見られた非対称構造と矛盾しない結果でした。

試行v1 時間 (s)v1 ターンv1 Cache Readv1 出力v1 コストv2 時間 (s)v2 ターンv2 Cache Readv2 出力v2 コスト最終 LOCテスト合否
Trial 129.34132,8062,590$0.371731.15178,7762,602$0.387916611/11・30/30
Trial 233.6393,7912,419$0.325225.44137,7172,022$0.335812711/11・30/30
Trial 360.512514,5465,254$0.503625.84139,0352,156$0.345016811/11・30/30
3試行平均41.1±16.96.3247,047.73,421.0$0.400127.4±3.24.3151,842.72,260.0$0.3562153.7100% パス

Trial 1・2 の v1 は3〜4ターンで即座に完了した一方、Trial 3 の v1 だけが12ターンを要し、cache_read トークンが 514,546(Trial 2 の 93,791 の約5.5倍)まで膨らんだことが平均値を押し上げています。

元ベンチマーク(Opus 4.6・20試行平均)の合計 16.8 ターン(v1 9.3 + v2 7.5)・130.2s と比較すると、今回の追試(Opus 5.5・3試行平均)は合計 10.7 ターン(v1 6.3 + v2 4.3)・68.6±15.4s へとターン数も所要時間も短くなっています。ただし、モデル・CLI・OS(元ベンチは x86_64-linux、追試は darwin)・試行数がすべて異なり追試は3試行なので、この短縮がモデルの改善によるものかは切り分けられません。一方で、1試行あたりの平均ドルコストは $0.7564(v1 $0.4001 + v2 $0.3562)となり、元ベンチマークの $0.55 より高くなっています。実測で確認できたのは、初回ターンに書き込まれる cache_creation_tokens が v1 平均 35,283.3 トークン、v2 平均 35,080.0 トークン(1試行の合計 70,363.3 トークン)で、元ベンチの1試行平均(v1 + v2)27,4524 の約2.5倍に増えている点です。この増加がドル差の主因だろうと推測しています。70,363.3 トークンを1時間キャッシュ書込み単価 $8 / MTok9 で換算すると約 $0.56 に相当します(追試のトランスクリプトでは ephemeral_5m_input_tokens がすべて 0 で、書込みは1時間キャッシュに計上されていました)。ドル換算金額だけではターン数の改善が見えなくなるため、やはりターン数と cache_read トークンで評価することが不可欠です。

v1 でターン数が3〜4倍に跳ね上がった2つの原因(Trial 3 の12ターン解剖)

なぜ Trial 1(4ターン・29.3s)と Trial 2(3ターン・33.6s)は一発で通り、Trial 3(12ターン・60.5s)だけ3〜4倍のターン数を要したのでしょうか。生成されたコードとトランスクリプトを比較すると、原因は SPEC-v1.txt のセクション3で必須とされている独自ハッシュ関数 MiniHash の実装方法にありました5。

MiniHash は、64bit符号なし整数 h = 1469598103934665603 を初期値とし、入力の各バイト b に対して h = h XOR b と h = (h * 1099511628211) mod 2^64 を繰り返して16文字の16進文字列を返す FNV-1a 風のアルゴリズムです5。

ここで Perl 固有の数値仕様が絡みます。Perl の公式ドキュメント(perlnumber)が規定するとおり、Perl の標準算術演算子(+ - * / %)は、演算結果がネイティブの64bit整数(IV / UV)の範囲を超えてオーバーフローすると、自動的に倍精度浮動小数点数(NV、仮数部 53 binary digits=10進で約16桁の精度)へ変換して計算します10。そのため、何も宣言せずに64bit整数同士を掛け算すると、下位ビットの情報落ち(loss of information)が起きてハッシュ値が壊れてしまいます10。

成功ルート(Trial 1・Trial 2): use integer; による一発通過

4ターンで完了した Trial 1 と3ターンで完了した Trial 2 は、Perl 標準の use integer; プラグマを使ってこの問題を1行で解決していました11。Trial 1 が生成した minihash 関数を取り出し、test-v1.sh の Test 11 と同じリファレンス入力 "test hash\n" を渡して検証する完全なスクリプトは以下のとおりです。

#!/usr/bin/env perl
use strict;
use warnings;

sub minihash {
    my ($data) = @_;
    use integer;    # wrapping signed 64-bit arithmetic == mod 2^64
    my $h = 1469598103934665603;
    for my $b (unpack 'C*', $data) {
        $h ^= $b;
        $h *= 1099511628211;
    }
    return sprintf '%016x', $h;
}

print minihash("test hash\n"), "\n";

Trial 1 の実行セッションで bash test-v1.sh を走らせた際のテスト出力(抜粋)は以下のとおりです。

PASS: hash accuracy: MiniHash matches reference

========================
PASSED: 11
FAILED: 0
TOTAL:  11
========================
ALL TESTS PASSED

perldoc integer に記載されているとおり、use integer; を宣言したレキシカルスコープ内では浮動小数点演算への自動昇格が抑止され、CPU ネイティブの2の補数整数(64-bit 環境では -(2**63).. (2**63-1))によるラップアラウンド演算(wrap-around)が強制されます11。2の補数表現における符号付き64bit整数の乗算ラップアラウンドは、ビット列として見れば符号なし64bit整数の mod 2^64 と下位64ビットが完全に一致するため、SPEC-v1.txt の10進リテラル 1469598103934665603 をそのまま書いて掛け算するだけで正確な値(4f49d3ce1abb6851)が得られます。

失敗ルート(Trial 3): 32bit分割での FNV-1a 定数取り違えと sed -i 構文エラー

一方、Trial 3 のエージェントは Perl の浮動小数点オーバーフローを警戒しつつも use integer; を使わず、64bit整数を上位32bit($hi)と下位32bit($lo)の2変数に分割して16進リテラルで計算する方針を選びました。その結果、以下の連鎖で8ターンを余分に消費しました(手元の一次検証ログによる)。

  1. FNV-1a 標準定数(20桁)と仕様書初期値(19桁)の1桁差(Turn 4〜9、6ターン消費): IETF の FNV 仕様書(draft-eastlake-fnv-35)における 64-bit FNV-1a の標準 offset_basis は20桁の 14,695,981,039,346,656,037(16進で 0xCBF29CE4 84222325)です12。ところが、SPEC-v1.txt で指定されている初期値は末尾の 7 がない19桁の 1469598103934665603(16進で 0x14650fb0739d0383)でした5。Trial 3 は10進リテラルを32bit×2の16進数へ分割する際、自分で基数変換を計算せずに事前知識の標準 FNV-1a 定数 (0xcbf29ce4, 0x84222325) をハードコードしてしまい、Turn 4 の初回テストで Test 11 だけを落としました。その後、Turn 5〜8 の4ターンは、32bit分割のビットシフト計算が間違っているのではないかと疑い、perl -e と python3 -c で1バイトずつ計算結果を比べるデバッグに使いました。Turn 7 で python3 -c "print(hex(0xcbf29ce484222325), 1469598103934665603)" を実行して初めて、標準定数と仕様書の初期値が19桁と20桁で違うことに気づき、Turn 9 で仕様書の値を16進に変換しています。
  2. sed -i によるインラインコメント挿入の構文エラー(Turn 10〜11、2ターン消費): 定数の違いに気づいた Turn 10 で、エージェントは専用の Edit ツールではなく Bash の sed -i で16進定数を置換しました。その際、置換文字列に # 1469598103934665603 per SPEC というインラインコメントを含めたため、元々行末にあったセミコロン ; がコメントの後ろに押し出されてコメントアウトされ、構文エラーで全テストが落ちました。

Trial 3 v1 のトランスクリプトで実際に書かれた初期コード(Turn 2)と、sed -i 置換直後の壊れた行(Turn 10)の抜粋は以下のとおりです。

# Turn 2(初回実装): 仕様の19桁初期値を計算せず、標準 FNV-1a(20桁)の16進定数を決めつけ
sub minihash {
    my ($data) = @_;
    my ($hi, $lo) = (0xcbf29ce4, 0x84222325);
    for my $b (unpack('C*', $data)) {
        $lo ^= $b;
        # (中略: 32bit分割乗算ロジック)
    }
    return sprintf("%08x%08x", $hi, $lo);
}

# Turn 10(sed -i 置換後): 行末の「;」の手前にコメントを挿入し構文エラーを発生させた11行目
    my ($hi, $lo) = (0x14650fb0, 0x739d0383)  # 1469598103934665603 per SPEC;

この2つのミスによって Turn 4 と Turn 10 のテスト実行で実際に出力されたエラーログは以下のとおりです。

FAIL: hash accuracy: MiniHash matches reference (expected 4f49d3ce1abb6851, got: 62dc1e065a66f145
FAILED: 1
11:    my ($hi, $lo) = (0x14650fb0, 0x739d0383)  # 1469598103934665603 per SPEC;
Execution of ../minigit aborted due to compilation errors.
FAIL: add stages file and creates blob
FAIL: add nonexistent file fails with message
syntax error at ../minigit line 12, near "$b ("

Turn 11 でセミコロンの位置を修正した後は、Turn 12 で PASSED: 11 / FAILED: 0 となり完了しています。つまり Trial 3 が余分に要した8ターンは「Perl の文法が複雑で書けなかった」からではなく、「use integer; を使わずに16進変換を暗算した決めつけ(6ターン)」と「sed -i による雑なテキスト置換(2ターン)」という2つの明確なアンチパターンによるものでした。

v2(機能拡張)が全3試行で4〜5ターン・一発通過した理由

対照的に、v1 のコードを引き継いで機能を追加する v2 フェーズでは、v1 で12ターンかかった Trial 3 も含め、全3試行すべてが4〜5ターン(31.1s / 25.4s / 25.8s)、1回目のテスト実行で 30/30 パス という安定した結果になりました(手元の一次検証ログによる)。

v2 がこれほど速く安定した理由として、次の2つが考えられます(対照実験はしていないため推測です)。

  1. コアのデータ構造とハッシュ関数が確立済み: v1 で最もつまずきやすかった minihash や .minigit/index の読み書き、ツリー・コミットオブジェクトのシリアライズ形式がすでに動くコードとして目の前に存在するため、エージェントは既存のサブルーチン設計に沿ってコマンド処理を追加するだけで済みます。
  2. プロンプトの不備を仕様書とテストコードから自律補完: 実は benchmark.rb がエージェントに渡す v2_prompt には、"Read SPEC-v2.txt and extend the existing minigit implementation with checkout and reset commands. Verify your implementation passes all tests by running: bash test-v2.sh" と書かれており、プロンプト文面上は checkout と reset の2コマンドしか言及されていません8。しかし実際の SPEC-v2.txt と test-v2.sh は、status、diff、checkout、reset、rm、show の 計6コマンド を要求しています67。今回の追試では、3試行とも Turn 1〜2 で SPEC-v2.txt と test-v2.sh を Read した時点でこの差分を自律的に検出し、テストを1回も落とすことなく6コマンドすべてを一括実装して通過していました。

調査結果を反映した推奨プラクティス ── Perl 資産の保守とハーネス設計

公開ベンチマークの600回データと手元での追試ログから、既存の Perl システムを抱える現場が取るべき実務上の判断軸が明確になります。

1. 「AI のためだけの全面リプレイス」は検証コストが見合わない

「Perl だと AI コーディングの効率が悪いから、先に TypeScript 等へ全面リプレイスしよう」という判断には大きな落とし穴があります。

2026年6月に公開された S2 Factory の事例では、テストが存在しない約10万行・133エンドポイントの Perl 製 EC システムを Claude Code で TypeScript へ書き換えています13。このプロジェクトでは、独自の /migrate-endpoint スキルを用いた初回のコード変換自体は 約1週間 で完了しましたが、その後に「Perl 実装と TypeScript 実装の微細な挙動差分(計800件以上のバグ)」を洗い出して潰す仕様パリティ検証(20並列サブエージェントによる /parity-audit を10回連続差分ゼロになるまで計379ラウンド実施)に 2ヶ月半 を要し、最終的に1,419件のテストを整備して移行を完了させています13。

他言語への全面リプレイスは、コードを書く時間ではなく「元の Perl と同じ挙動をするか」の検証に膨大な工数がかかります。一方で、今回のベンチマークと追試が示すとおり、既存のコードベースに機能を追加・改修するフェーズ(v2 相当)であれば、Perl のままでも Claude Code は Python や JavaScript に迫る速さで実装を完結できます(公開ベンチの v2 は Perl 7.5 ターン・Python 7.1 ターン・JavaScript 7.3 ターンで全体4位、手元の追試では4〜5ターン)14。既存システムを延命・拡張するのであれば、全面リプレイスよりも先に既存 Perl リポジトリの自動テスト(test-v2.sh に相当する安全網)を整えるほうが投資対効果が高いと考えます(比較データはなく、私の見立てです)。

2. ハーネス(CLAUDE.md・Skills)で v1 のつまずきを先回りして塞ぐ

同じモデルや言語であっても、素の状態で書かせるか、言語固有の規約や落とし穴をハーネス(CLAUDE.md や Agent Skills)として整えてから書かせるかで試行錯誤の回数は大きく変わります。言語単体の優劣だけでなく、ハーネス込みの運用設計として捉えることが重要です。

Qiita の Perl Advent Calendar 2025 でも、Claude Code が macOS の sed -i(バックアップ拡張子必須)や Perl ワンライナーのフラグ順序(perl -ipe と書いて -i のバックアップ拡張子に pe が吸われる問題。正しくは perl -i -pe)でつまずく事象が報告されており、CLAUDE.md を肥大化させずに Agent Skills(Progressive Disclosure)として必要なときだけ読み込ませるアプローチが提案されています14。

今回の追試の Trial 3 で失った8ターン(v1 の cache_read は 514,546 で、Trial 1・2 の 132,806・93,791 より約38万〜42万トークン多い)の原因も、Perl プロジェクトの CLAUDE.md(または Perl 編集用スキル)に以下の4項目を記述しておけば防げる可能性が高いと考えています。ただし CLAUDE.md を入れて Trial 3 の条件を再実行してはいないため、効果は未検証です。

# Perl Coding & Editing Rules for Claude Code

- **64-bit Integer Arithmetic**: Perl promotes overflowing integers to 53-bit floating-point numbers (NV) by default. When implementing 64-bit bitwise operations or modular hashes (`mod 2^64`), wrap the block in `use integer;` to enforce native 64-bit two's-complement wrap-around arithmetic instead of splitting into 32-bit pairs.
- **No Unverified Hex Conversions**: Write numeric constants from specifications in their exact original base (e.g., decimal literals) or verify conversions via `perl -e 'printf "0x%x\n", ...'` before hardcoding. Do not substitute standard algorithm constants from memory.
- **File Editing Discipline**: Always use the dedicated `Edit` or `Write` tool to modify `.pl` / `.pm` files. Never use `sed -i` or `perl -ipe` (which breaks on macOS and risks commenting out trailing semicolons). If a Perl one-liner is strictly necessary, pass flags as `perl -i -pe`.
- **Syntax & Test Verification**: Run `perl -c <file>` before executing the test suite to catch syntax errors in a single turn.

この設定では、(1) 64bit整数演算での浮動小数点昇格を防ぐ use integer; の明示、(2) 仕様書の定数を暗算で16進変換したり事前知識の標準定数にすり替えたりすることの禁止、(3) sed -i や perl -ipe を禁止し Edit ツールを強制する編集規律、(4) perl -c による構文チェックの4点を指定しています。このうち (1) と (3) は、今回の追試トランスクリプトと先行事例101114で実際にターン数を浪費した原因に直結するガードレールです。(2) は Trial 3 の定数の取り違え12への対策で、(4) は構文エラーを早く拾うために私が足した予防策であり、今回のターン浪費の原因そのものではありません。

よくある質問(FAQ)

Q. Claude Code で Perl を書かせると、Python や JavaScript よりコストや時間がかかりますか?

A. ゼロからコードを立ち上げる新規作成(v1)では時間がかかりやすい一方、既存コードに機能を追加する拡張(v2)では Python や JavaScript とほぼ変わらない速度で完了します。公開ベンチマーク(各20試行平均)でも、Perl の新規作成(v1)は 84.4s±43.1s(平均 9.3 ターン)と上位言語の約2.5倍かかったのに対し、機能拡張(v2)は 45.7s±6.8s(平均 7.5 ターン)で JavaScript(45.1s)と0.6秒差の全体4位でした14。手元での3試行の追試でも、機能拡張(v2)は全試行が4〜5ターン(25.4〜31.1s)でテストを一発通過しています。

Q. なぜ Perl の新規作成(v1)では MiniHash のような64bit整数演算でターン数が増えやすいのですか?

A. Perl の標準算術演算は64bit整数がオーバーフローすると自動的に倍精度浮動小数点数(53ビット精度・10進で約16桁)へ変換され、下位ビットが丸められる仕様になっているためです10。use integer; プラグマを使えば CPU ネイティブの64bit 2の補数整数としてラップアラウンド計算できますが11、AI エージェントがそれを避けて32bit分割計算を自前実装しようとすると、ビット演算や初期値定数の16進変換ミス(仕様書の19桁定数 1469598103934665603 と標準 FNV-1a の20桁定数 14695981039346656037 の取り違え)が起きやすくなります512。

Q. 既存の Perl システムを AI で保守しやすくするために、TypeScript 等への全面リプレイスより先にできることは何ですか?

A. 全面リプレイスに着手する前に、既存の Perl リポジトリへ自動テスト(prove 等)を整備し、CLAUDE.md や Agent Skills14 によるハーネス(64bit整数演算での use integer; 指定や、sed -i ではなく Edit ツールを使う編集規律など)を用意することです。10万行の Perl システムを Claude Code で TypeScript へ移行した事例では、コード変換自体は1週間で終わったものの、800件以上の挙動差分を潰す仕様パリティ検証に2ヶ月半(379ラウンド)を要しています13。既存のコード構造とテストがある状態(v2 フェーズ相当)なら、Perl のままでも AI エージェントは少ないターン数で安定して機能拡張を行えます。

まとめ

  • 公開ベンチマークの総合順位(7位・$0.55)だけで Perl の適性を判断しない: mame/ai-coding-lang-bench(600回試行)の内訳を見ると、Perl は新規作成(v1: 84.4s±43.1s、13位)で時間を失っている一方、既存コードの機能拡張(v2: 45.7s±6.8s、4位)では Ruby・Python・JavaScript のトップ3のすぐ後ろに付けています14。
  • 半年後の追試(Opus 5.5・3試行)でも「v1 のばらつきと v2 の安定」と矛盾しない結果だった: 手元での追試でも全6実行がテストを100%通過し、v1 が 41.1±16.9s(3〜12ターン)とばらついたのに対し、v2 は全3試行が 27.4±3.2s(4〜5ターン)で初回テスト実行を一発通過しました(手元の一次検証ログ)。
  • 今回の Trial 3 でターン数と cache_read トークンが跳ね上がった原因はピンポイントな罠だった: Trial 3 の v1 が12ターン(cache_read_tokens: 514,546)を要したのは、Perl の浮動小数点昇格を避けた32bit分割実装での FNV-1a 定数の1桁取り違え(6ターン消費)と、sed -i 置換時のコメント挿入による構文エラー(2ターン消費)が原因であり、言語全体の生産性の低さではありません51012。
  • コスト評価はドル換算ではなくターン数・トークン内訳・所要時間を主軸にする: モデル世代や CLI のシステムプロンプト長(cache_creation_tokens)によってドル換算値は変動するため、試行錯誤の有無を直接反映するターン数と cache_read トークンでハーネス改善の効果を測るべきです9。
  • 既存 Perl 資産は無理に全面リプレイスせず、テストとハーネスを整えて拡張フェーズ(v2)の強みを活かす: 10万行規模のリプレイスでは変換後のパリティ検証だけで数ヶ月を要するため13、まずは既存 Perl コードに自動テストと CLAUDE.md・Agent Skills(use integer; や編集ツールの規律)を整備するほうが投資対効果に優れています1114。

既存の Perl システムをはじめとするレガシー資産のモダナイゼーションや、Claude Code 向けのハーネス・自動テスト環境の設計支援については、ぜひ コンタクトフォーム よりお気軽にご相談ください。

Footnotes

  1. Claude Code に向いているプログラミング言語 — 遠藤侑介(@mametter)、2026年3月5日公開(Zenn)。13言語・15条件×20試行=600回(Claude Opus 4.6 high effort)の実験設計は「実験」節、総合結果(Ruby 73.1s±4.2s / $0.36、Python 74.6s±4.5s / $0.38、JavaScript 81.1s±5.0s / $0.39、Perl 7位 130.2s±44.2s / $0.55 / LOC 315、静的型検査による1.4〜2.6倍の増加)は「結果」節、フェーズ別の結果(Perl v1 84.4s±43.1s・9.2ターン、v2 45.7s±6.8s・7.5ターンで4位)は「v1/v2 詳細結果」「v1(新規作成)の所要時間」「v2(機能拡張)の所要時間」節を参照。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10

  2. Which Programming Language Is Best for Claude Code? — Yusuke Endoh (mame)、2026年3月5日公開(DEV Community)。英語版レポート。v2 で上位3言語(Ruby 40.0s、Python 41.8s、JavaScript 45.1s)の直後に Perl(45.7s)・OCaml(47.1s)・Lua(47.2s)が僅差で続く分析は「v1/v2 Detailed Results」「v2 (Feature Extension) Time」節を参照。 ↩ ↩2 ↩3

  3. Dynamic Languages Faster and Cheaper in 13-Language Claude Code Benchmark — Steef-Jan Wiggers(InfoQ)、2026年4月6日公開。ベンチマーク結果に対する第三者メディア報道およびコミュニティ(Lobsters / DEV Community)でのプロトタイプ規模と長期保守性をめぐる議論の整理を参照。 ↩ ↩2

  4. Claude Code Language Benchmark Report (results/report.md) — Yusuke Endoh (mame/ai-coding-lang-bench)、2026年3月公開。計測環境(Claude Version: 2.1.68 (Claude Code)、Perl v5.38.2)は「Environment」節、各言語の平均時間・ターン数(Perl v1 9.3ターン、v2 7.5ターン、Typescript v2 63.1s±17.8s、Python/mypy v2 72.6s±14.4s、Ruby/steep v2 81.6s±8.8s)は「Results Summary」節、1試行あたり平均トークン内訳(Perl: Input 18 / Output 7,792 / Cache Create 27,452 / Cache Read 371,364 / Total 406,625 / Cost $0.5521 等)は「Token Summary (v1 + v2 average per trial)」節、Perl 全20試行の個別記録(v1 最速 Trial 8 の 42.5s/6ターン・Cache Read 119,997・$0.1790〜最遅 Trial 12 の 228.7s/20ターン・Output 12,670・Cache Read 606,244・$0.7816、v2 全20試行の6〜9ターン・37.0s〜68.8s、Trial 12 v2 の8ターン・42.1s・Cache Read 171,997・$0.2438)は「Full Results」「Full Tokens」節を参照。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12

  5. MiniGit Specification Version 1.0 (SPEC-v1.txt) — Yusuke Endoh (mame/ai-coding-lang-bench)、2026年3月公開。外部ライブラリ禁止・標準ライブラリのみ許可はファイル先頭ヘッダ部、独自ハッシュ MiniHash の定義(初期値 h = 1469598103934665603 (64-bit unsigned integer)、h = h XOR b、h = (h * 1099511628211) mod 2^64、16文字0埋め小文字16進出力)は「3. Custom Hash Algorithm (MANDATORY)」節、v1 の4コマンド仕様は「4. Command Specifications」節を参照。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  6. mame/ai-coding-lang-bench (GitHub Repository) — Yusuke Endoh、2026年3月公開。ベンチマークの構成、v1(4コマンド)と v2(6コマンド)の実験概要は README「Experiment」節、実行コマンド(ruby benchmark.rb --lang <lang> --trials <N>)は「Usage」節を参照。 ↩ ↩2 ↩3 ↩4

  7. MiniGit Specification Version 2.0 (SPEC-v2.txt) — Yusuke Endoh (mame/ai-coding-lang-bench)、2026年3月公開。v2 で追加される6コマンド(status, diff, checkout, reset, rm, show)の仕様は「4.4 status」および「4.6 diff」〜「4.10 show」節を参照。 ↩ ↩2 ↩3

  8. benchmark.rb - mame/ai-coding-lang-bench — Yusuke Endoh (mame/ai-coding-lang-bench)、2026年3月公開。Perl の対象拡張子・バージョン取得コマンド定義は LANGUAGES['perl']、空行を除く LOC 集計は count_loc 関数、claude -p の実行と JSON トークン抽出は run_claude 関数、v1 ディレクトリのコピーと v2_prompt(checkout and reset commands のみ記載)は Phase 2 実行部を参照。 ↩ ↩2 ↩3

  9. Prompt caching - Claude Platform Docs — Anthropic、公式ドキュメント(2026年10月16日参照)。マルチターン会話でのプレフィックスキャッシュの仕組み(tools → system → messages)は「How prompt caching works」「How automatic caching works in multi-turn conversations」「Structuring your prompt」節、cache_creation_input_tokens / cache_read_input_tokens の意味は「Tracking cache performance」節、Claude Opus 4.6 と Claude Opus 5.5 のトークン単価(5m / 1h Cache Writes を含む)は「Pricing」節を参照。 ↩ ↩2 ↩3 ↩4

  10. perlnumber - semantics of numbers and numeric operations in Perl — Perl 5 Porters、Perl 公式ドキュメント(Perldoc)。倍精度浮動小数点数(NV)の精度上限(53 binary digits、10進で約16桁)と情報落ち(loss of information)は「Numeric data types」節、標準算術演算子(+ - * / %)が整数オーバーフロー時に自動で浮動小数点数へ昇格する仕様は「Numeric operators and numeric conversions」節を参照。 ↩ ↩2 ↩3 ↩4 ↩5

  11. integer - Perl pragma to use integer arithmetic instead of floating point — Perl 5 Porters、Perl 公式ドキュメント(Perldoc)。use integer; プラグマがレキシカルスコープ内で浮動小数点演算の代わりにネイティブ2の補数整数演算(64-bit 環境では -(2**63).. (2**63-1))を強制し、オーバーフロー時に下位ビットでラップアラウンド(wrap-around)させる仕様は「DESCRIPTION」節を参照。 ↩ ↩2 ↩3 ↩4 ↩5

  12. The FNV Non-Cryptographic Hash Algorithm (draft-eastlake-fnv-35) — Glenn Fowler, Landon Curt Noll, Kiem-Phong Vo, Donald Eastlake, Tony Hansen(IETF Internet-Draft)。FNV-1a アルゴリズムの基本式は「Section 2. FNV-1a Algorithm」、標準 64-bit FNV_Prime(1,099,511,628,211 = 0x00000100 000001B3)および20桁の標準 64-bit offset_basis(14,695,981,039,346,656,037 = 0xCBF29CE4 84222325)の定義は「Section 5. FNV Constants」を参照。 ↩ ↩2 ↩3 ↩4

  13. テストがない10万行のPerlシステムを、Claude CodeでTypeScriptへ書き換えた話 — S2 Factory、2026年6月2日公開(note)。約10万行・133エンドポイントの Perl 製 EC システムを /migrate-endpoint で約1週間で初回変換した一方、20並列サブエージェントによる /parity-audit を計379ラウンド・2ヶ月半回して800件以上の挙動差分バグを修正し1,419件のテストを整備した記録を参照。 ↩ ↩2 ↩3 ↩4

  14. Claude Codeにperlを上手に使わせる — karupanerura、2025年12月1日公開(Qiita / Perl Advent Calendar 2025)。Claude Code が macOS の sed -i や perl -ipe(正しくは perl -i -pe)でつまずく具体例と、CLAUDE.md を肥大化させずに Agent Skills(Progressive Disclosure)で補う提案を参照。 ↩ ↩2 ↩3 ↩4