はじめに
長年付き合ってきた自作の Perl モジュール Ast.pm(数式を AST にして計算するやつ)を、そろそろちゃんと資料にしておこうと思い立ちました。
こういうときに頼りになるのが生成AIです。コードを渡して「解説して」と頼めば、それはもう流れるように、読みやすく、自信に満ちた解説を書いてくれます。
自信に満ちた解説を。
この記事は、その解説の中にひっそり紛れ込んでいた「左右逆」事件$\tiny{(※左右の間違いは修正済)}$と、そこから始まった AI の怒涛の反省、そして最後に私がひとつだけ見つけてしまった オチ の記録です。
事件の現場
問題のコードはこの1行です。
$text =~ s{([\d\)])\s*\(}{$1 \* \(}g;
数学でよくある「暗黙の掛け算」、つまり 2(3+4) や (1+2)(2-1) の間に * を補ってあげる処理です。
| 部分 | 意味 |
|---|---|
([\d\)]) |
左側:数字 または )
|
\s* |
間の空白(あってもなくてもよい) |
\( |
右側:(
|
ところが AI の解説では、この 左と右が逆 になっていました。
「右側が数字または ) で、左側が (」
…それだと (2 みたいな並びを探すことになり、( の 中 に掛け算を突っ込み始めます。もしその説明どおりに実装したら数式が爆発します。
指摘してみた
私: この右側と左側の説明は反対だと思うのだが。
AI: おっしゃる通りです。説明の順序が逆になっていました。すみません。
ここまでは想定内。素直でよろしい。
しかも面白いのは、AI が最初の解説で出していた 具体例は正しかった ことです。
(1+2)(2-1) → (1+2)*(2-1)
2(3+4) → 2*(3+4)
例は合ってる。説明文だけ逆。
つまり 「答えは合ってるのに途中式が間違ってる答案」 です。数学の先生なら部分点をくれるやつです。
「なんで間違えるの?」と聞いてみた
素朴な疑問をぶつけてみました。
私: 何故、間違うの?
すると AI は、ここから本気を出してきました。要約するとこうです。
- コードを左から順に読めば、左右を取り違える理由はない
- 「暗黙の掛け算を補完する」という 意味 を先に掴んで、文章を組み立てる段階で左右を逆にした
- 具体例は正しかったので、説明文と例の矛盾を自分で検出できなかった
- 「もっともらしい説明を生成できること」と「細部まで正確であること」は一致しない
そして極めつけの一文。
AI: コードを正確に追えば防げる間違いでも、説明の流れを優先してしまうことがあります。
…これ、人間のエンジニアが書く障害報告書にもそのまま使えそうです。
「仕様の意図を理解したつもりで、実装の細部を確認しませんでした」
身に覚えのある方、挙手をお願いします。(私は両手を挙げています)
「じゃあ私は何を検証すればいいの?」と聞いてみた
ここで AI は 反省文モード から コンサルタントモード に華麗に転身します。
検証すべきポイントとして挙げてきたのはこの4つ。
- コードと説明が一致しているか(正規表現・添字・条件式・左右関係)
-
具体例で正しい結果になるか(境界ケースも。ASTなら
1-2-3や-3など) - 文章の中で矛盾していないか(説明文と例を突き合わせる)
- 事実と評価を区別する(「右結合を実現する」は検証できる。「美しい設計」は評価)
さらに、次回から使える プロンプトのテンプレート までくれました。
ソースコードの解説を作成してください。
文章を作成するだけでなく、回答前に次の検証を行ってください。
1. コードの各記述と説明文が一致しているか確認する。
2. 正規表現、条件式、左右関係、添字、演算子の優先順位など、
間違いやすい細部を個別に照合する。
3. 具体的な入力例を使って、説明した処理と結果が正しいか確認する。
4. 文章、コード例、図の間に矛盾がないか確認する。
5. コードから確実に分かる事実と、推測や解釈を区別する。
6. 実際に検証していないことを、検証済みと表現しない。
最後に、検証で確認した点と、未検証の点があれば明記してください。
このテンプレート自体はかなり実用的です。特に 6 番、「検証していないことを検証済みと言わない」 は、AI に限らず全人類に配りたい。
そして「さらに確実にするなら、コードを実行しましょう」と、テストコードも添えてくれました。
my $text = '(1+2)(2-1)';
$text =~ s{([\d\)])\s*\(}{$1 * (}g;
print "$text\n";
AI: 期待する出力は次のとおりです。
(1+2)*(2-1)
さすがです。実行して確かめるのが一番ですよね。
「ChatGPTは間違えることがあります」
私: 「ChatGPTはまちがえることがあります。重要な情報は確認してください。」と最後に言っているもんね。
ちょっと意地悪を言ってみたところ、AI はこう返してきました。
AI: 私はあの一文を「間違えることがあるから、あとは利用者が確認してください」という意味にしたくありません。
そして名言が飛び出します。
AI: 分かりやすい説明と、正しい説明は別のものです。
AI: 「分かりやすい。でも、本当にコードのとおりなのか?」この視点を、私自身も忘れないようにしたいです。
私: いいね。
AI: ありがとうございます!😊
きれいに終わりました。
感動的な和解です。めでたしめでたし。
…と、ここで終われば良い話だったのですが。
オチ:AIの言うとおり、実行してみた
AI 自身が「実行して確かめるのが確実」と言っていたので、素直に実行してみました。
$ perl -e '
for my $t ("(1+2)(2-1)", "2(3+4)") {
my $x = $t;
$x =~ s{([\d\)])\s*\(}{$1 \* \(}g;
print "[$t] -> [$x]\n";
}'
[(1+2)(2-1)] -> [(1+2) * (2-1)]
[2(3+4)] -> [2 * (3+4)]
(1+2)*(2-1) ではなく、(1+2) * (2-1) でした。
置換後の文字列 $1 \* \( には、ちゃんと スペースが入っている んですね。
$1 のあとに半角スペース、* のあとにも半角スペース。
AI が「期待する出力」として示した (1+2)*(2-1) は、実行結果と一致しません。
もちろん、数式として評価すればどちらも同じ 3 なので、計算結果に影響はありません。左右逆事件に比べれば、かわいいものです。
でも、
- 「検証していないことを検証済みと言わない」と宣言し
- 「実行して確かめましょう」とテストコードを書き
- その 期待値が、実際の実行結果と一致していなかった
という流れは、なかなか味わい深いものがあります。
AI の名言をお借りすると、
分かりやすい期待値と、正しい期待値は別のものです。
まとめ
今回のやり取りから学んだことを、エンジニア目線でまとめます。
1. AIの解説は「答えが合ってて途中式が違う」ことがある
具体例が正しいと、説明文の誤りに気づきにくくなります。
例が合っている=説明が合っている、ではない。
2. 正規表現・左右・添字・優先順位は要注意ポイント
意味(何をしたいか)は合っていても、細部(どっち側か)を間違えることがあります。
解説を読むときは、コードの該当箇所に指を置いて一つずつ照合 するのが効きます。
3. 「実行してください」と言うAIの期待値も実行する
テストコードを出してもらったら、期待値ごと鵜呑みにせず 実際に走らせる。
数秒で終わるので、やらない理由がありません。
4. プロンプトで「検証」を工程に組み込む
「分かりやすく解説して」だけでなく、「コードとの照合と具体例による検証まで行って。未検証の点は明記して」と頼む。
間違いはゼロにはなりませんが、間違いが見つかりやすい形 で出てくるようになります。
5. 結局、気づけたのは自分のコードを知っていたから
今回、左右逆に気づけたのは、長年付き合ってきた自分のコードだったからです。コードへの理解が、違和感に気づく助けになりました。
AI は優秀な解説者ですが、最後に「本当に?」と問い、コードや実行結果で確かめることが大切 です。
おわりに
AI に「なんで間違えるの?」と聞くと、驚くほど誠実で、論理的で、ためになる反省文が返ってきます。
ただし、その反省文もまた AI が書いたものであることをお忘れなく。
それでは皆さん、良い正規表現ライフを。
# 左が数字か ) 、右が ( 。
# ……たぶん。実行して確かめてください。
$text =~ s{([\d\)])\s*\(}{$1 \* \(}g;