AI からコードの役に立つ説明を得るには、自分がすでにどれだけ知っているかを伝え、1行ずつの説明を頼み、トレース(コードの実行中に各変数が持つ値の表)を頼みます。「このコードを説明して」だけでは、架空の平均的な読み手に向けた要約が返ってきて、たいていあなたには基本的すぎるか速すぎます。
1行ずつ、値のトレースつきで
2つのタブは、同じ短い関数について尋ねています。それぞれの返答で何が確かめられるかを比べてください。
def running_max(nums):
result = []
best = None
for n in nums:
if best is None or n > best:
best = n
result.append(best)
return result
print(running_max([3, 1, 4, 1, 5]))この関数はリストの累積最大値を計算します。数をループで順に見ていき、それまでに見た最大の値を best に保持し、各ステップでその値を result に追加します。best is None のチェックは最初の要素を扱うためのものです。この呼び出しは [3, 3, 4, 4, 5] を表示します。
各要素を1回ずつ見るので、この関数の計算量は O(n) です。
1つ目の返答は正確ですが、累積最大値が何かをすでに知っている人にしか役立ちません。誰も頼んでいない計算量のメモまで付いています。誰が読んでいるのかをモデルが知らないときに付いてくる、よくある余分です。2つ目の返答はすべての文を指させる1行に結びつけ、要約ではさらりと触れるだけのことを表が具体的にしています。result.append(best) は best が変わらない周も含めて毎周実行されます。3 が2回現れるのはそのためで、「各ステップで」から推測する代わりに、表の2行目で見て取れます。
トレース表は、説明そのものの確認にもなります。ループの中に print(n, best, result) を入れて実行すれば、各行を確かめられます。ある行が実際の出力と食い違えば、説明はどこかで間違っていて、しかもどこかがわかります。
自分のレベルに合わせて説明してもらう
説明を頼むプロンプトで最も役立つ1行は、自分がすでに何を知っているかです。モデルに、どの行を飛ばし、どの行でゆっくり進むべきかを伝えます。役割の一文(「あなたはプログラミングを始めて1か月目の人を教える講師です」)も役立ちますが、仕組みは同じで、読み手が誰かをモデルに伝えています。役割で何が変わり何が変わらないかはロールプロンプティングで扱っています。
このブロックは再利用できる版です。レベル、わからない部分、コードを変えれば、説明もそれに合わせて変わります。
text = "the cat and the hat"
counts = {}
for word in text.split():
counts[word] = counts.get(word, 0) + 1
top = sorted(counts.items(), key=lambda kv: kv[1], reverse=True)[:2]
print(top)ループは各単語を数えます。counts は最終的に {'the': 2, 'cat': 1, 'and': 1, 'hat': 1} になります。
では最後の2行を、内側から見ていきます。
counts.items()は('the', 2)、('cat', 1)、('and', 1)、('hat', 1)の組を返します。lambda kv: kv[1]は名前のない小さな関数です。組を1つ受け取り、その2番目の要素、つまり回数を返します。('the', 2)なら2を返します。sorted(..., key=...)は、その関数が返すもので組を並べ替えるので、回数で並べ替えます。reverse=Trueで大きいものが先になります。回数が同じ単語は、元の順番を保ちます。[:2]は最初の2組を残します。
つまり top は [('the', 2), ('cat', 1)] で、それが表示されます。
「回数が同じ単語は元の順番を保つ」は、手短な説明では省かれる細部で、and や hat ではなく cat が2位になる理由です。Python の sorted は安定ソートで、reverse=True でもその安定性は保たれます。自分では尋ねようと思わないことですが、「この入力に対してその部品が生み出す値」を頼んだことで表に出てきました。
ファイル全体ではなく、1つの部分について尋ねる
500行のファイルを貼り付けて「これは何をしているの」と尋ねると、ファイルの構成の案内が返ってきます。1つの関数で行き詰まっているなら、その関数とそれを呼び出している行を貼り付け、直接尋ねてください。「リストが空のとき、この関数が早めに return するのはなぜですか?」や「12行目の yield は何をしていて、return だったら何が変わりますか?」。狭い質問にはあなたのコードについての答えが返り、広い質問にはあなたのコードに似たコードについての答えが返ってきます。
見慣れない大きなコードベースなら、逆の順番にします。まず地図を頼み(「主なモジュールと、それぞれが担当していることを1行ずつ挙げて」)、それから必要なモジュールについて尋ねます。これは小さなプロンプトチェーンで、各ステップでモデルの答えを確認できる短さに保てます。
知っている言語を通して説明してもらう
見慣れない言語のコードは、知っている言語を基準にして説明してもらうと読みやすくなります。プロンプトにそう書いてください。「Python は知っています。この Go の関数を説明し、Python のプログラマーが予想するのと違う動きをするところをすべて指摘してください。」誤解が潜んでいるのはその違いです。整数の割り算、None の代わりのゼロ値、元の配列とメモリを共有するスライス。Go のコードをふつうに説明するだけでは、そうした行を正しく説明しても、あなたの直感がそこで間違っていることは教えてくれません。
理解できたかを確かめる
読んで納得した説明でも、自分でそのコードを書けるようになっているとは限りません。そのすき間を埋めるプロンプトが2つあります。
- 先に予想する。 コードを実行したり説明を頼んだりする前に、何が表示されると思うかを書き留めます。そのあと、予想が外れた行だけを説明するようモデルに頼みます。
- 自分で説明し直す。 自分の説明を書き、書き直さずに、間違っているところや足りないところを指摘するようモデルに頼みます。
def running_max(nums):
result = []
best = None
for n in nums:
if best is None or n > best:
best = n
result.append(best)
return result
私が本当に理解しているかを確かめる質問を3問、1問ずつ出してください。そのうち1問は、新しい入力に対する出力を予想させる問題にしてください。次の質問をする前に私の答えを待ち、答えが正しいかどうかとその理由を教えてください。第1問(全3問):running_max([2, 7, 5, 9]) は何を返しますか?実行する前に考えてみてください。
同じやり方はプログラムがおかしな動きをしているときにも使えますが、そのときに欲しいのは授業ではなく原因です。デバッグのためのプロンプトを参照してください。目の前のコードを AI が書いたのなら、1行ずつの説明は、それを採用する前に手早くレビューする方法になります。ほかに実行すべき確認はコードを書くためのプロンプトに挙げています。
よくある質問
ChatGPT や Claude にコードを説明してもらうにはどう頼めばいいですか?
コードを貼り付けて、3つのことを伝えます。すでに知っていること、わからない部分、どんな形の説明が欲しいかです。「各行を1文で説明し、そのあとループが1周するごとの変数の値を表で示して」と頼めば、「このコードを説明して」よりはるかに役立つ答えが返ってきます。
トレース表とは何ですか?
トレース表とは、実行中のプログラムを追いかける表です。ステップ(多くはループの1周)ごとに1行、変数ごとに1列を設け、その時点での各変数の値を書きます。これを頼むと、抽象的な説明が、コードと照らし合わせて確かめられる具体的な値に変わります。プログラムをステップ実行するときにデバッガが見せてくれるものを書き記したものです。
知らない言語のコードも AI に説明してもらえますか?
もらえます。これは頼んで最も役に立つことの1つです。知っている言語を挙げて比較させてください。「Python は知っています。この Rust のコードを説明し、Python と違う動きをするところを指摘してください。」言語の動作についての説明は細部で自信たっぷりに間違えることがあるので、小さな例を実行して確かめてください。
AI にコードを説明してもらうのは学習に悪いですか?
そのあと何をするかによります。説明を読んで次に進むだけでは、ほとんど身につきません。実行する前に出力を予想する、モデルにクイズを出してもらう、コードを自分の言葉で説明し直して間違いを指摘してもらう。どれも自分で考えることを求め、学習が起きるのはそこです。