アルゴリズムよさようなら
まずは、以下のビデオを見ていただきたい。
私が、まだプログラマになりたての頃、IBMの大型機の端末にこんな具合で大きく時間を表示している人がいた。HP95LXという1991年に発売された超小型パソコンの表計算ソフトで、やっぱりこんな感じで時計を表示するサンプルマクロもあった。
仕事の道具を、ちょっとだけ遊び心をもって違うことに使ってみるのは楽しい。そんな気分で、エクセルでもこんな時計表示をやってみたいと思っていたのだが、そのままになっていた。それが、ChatGPTに頼んでみるとスルスルとVBAのコードが出てきて、30分ほどでちゃんと動くものになっていた。
VBAの達人の方々ならともかく、私のようにふだんVBAに親しんでいない人間としては画期的なことである。しかも、ふだんのプログラミングとは比べようもなくラクである。
生成AIによって、プログラミングの世界が大きく変化することになると思う。前回の「ChatGPTでプログラミングのフラット化がはじまっている」に続いて、ChatGPTでコードを生成して動かす。今回は、その基本テクニックを紹介したいと思う。
どう動かすかではなく何を作りたいかを伝える
私が、このVBAを書いてもらうためにChatGPTに与えたプロンプトは次のようなものである。
EXCELのVBAで時計を表示するコードを書いてください。
「時」と「分」と「秒」を表現する数字は、16行×3列のセルを黒で塗ることで表現します。
数字の「2」は、以下のパターンで「1」に相当するセルは塗る、空白は塗らないで表現します。11
1
1
1
1
1
1
1
11
1
1
1
1
1
1
111
時、分、秒の間に「:」を16行×1列で次のパターンで表現します。1が塗り、空白は塗らない。
1
1
1
1
各数字や「:」の間は1列空いているものとします。
1分に1回時間を更新してください。
ChatGPTによるコードの生成は、まだ始まって数カ月の発展段階にある。プログラミングは、この業界にとっては飯のタネの根幹をなすものなので、みんなやっていたとしても黙ってノウハウを蓄積しているのかもしれない。あるいは、コード生成できるのは知ってはいても、いままでゴリゴリ書いてきたスタイルを維持するほうが安全と考えているのかもしれない。
コード生成のための《プロンプトエンジニアリング》というものがあるわけだが、いわば、《プロンプトプログラミング》というような確立されたジャンルになると思う。それは、いま見えている範囲で書き出すと、次のような特徴がある。
1)手順やアルゴリズムで書くのではなく問題を表現する
2)人に伝えるように例示を使って説明する
3)参考になるコードがあればそれを与えて理解を促す
4)対話的(段階的)にすすめる
もちろん、手順やプロセス、あるいはアルゴリズムをChatGPTに伝えることもできる。そのほうが有効な場合はそうするとよいだろう。しかし、ChatGPTプログラミングでは、「こんなものが作りたい」と問題を定義するように伝えるのがよい。
理由ははっきりしていて、そのほうが人間もラクだし誤解がないからだ。3つの数字を並べ変えるとき「大きい順に並べる」と書くほうが、並べ変える手順を伝えるより間違いがないのは明らかだ。いわば《静的》なプログラミングができる。これが、プロンプトプログラミングの最大のメリットだと思う。
IFやWHILEや変数の組み合わせによるアルゴリズムがこんがらがってバグになる。私ば、7年ほど「全国小中学生プログラミング大会」に関わってきたが、子どもたちの「プログラムが動かなくて苦労した」とか「何度も投げ出したいと思った」といった声を聴くたびに、心が痛むのだった。
そのいまいましい世界から人々が救い出されるというだけでも、《静的》なプログラミングには意味がある。ちょうど、作りたいプログラムの概念をリングノートに鉛筆でスケッチするような、絵のような《静的》さかげんだ。
すべてを《ことば》だけで説明するとしたらそのための《言語力》のほうがよほど大変では? という意見もありそうだが、次の《例示》と《コードを与える》で解決することも多い。
《例》を示してやる――まさにプロンプト的な
次に、いかにもChatGPTプログラミング的といえるのが、《例示》を積極的に使うことだ。これは、OpenAIも言っていることでプロンプトエンジニアリングの基本の1つである。今回の例では、数字の「2」を表示する例をあげて、ほかもこんな調子でやってねと伝えている部分である。
ちなみに、私は「2」の例をプロンプトで与えたのだが、ChatGPTが書きだしたコードでは「0」が生成されていた。ほかの数字については自分で書いてねときたのだが、頼めばすべての数字を生成してくれそうである(今回は、1、3~9のフォントは自分でコードに書き加えたのだが)。
ChatGPTはプログラムのコードもむしゃむしゃと食べているらしい
ChatGPTには、人間の言葉だけでなくコードを与えてしまうことは、すでに裏技的に行われていたことだ。彼らは、プログラムのコードも学習していて与えたコードを理解することができる。その例として、さきほどのVBAにタイマー機能を追加することをこの手法でやってみることにする。
パソコンの画面に時分秒が大きく出るならば、ハッカソンなどのイベントで、ハックタイムなどの終了までの時間を表示するやつを作ってみたくなる。同じセッションで続けて、タイマーを追加してほしいとプロンプトを与えてもよいのだが、新たなセッション(画面左上から「+ New Chat」を選ぶ)でもよい。私がChatGPTに与えたプロンプトは、次のようなものだった。
以下のコードでエクセルのVBAとして時計が動いています。
これを改造して時刻とタイマーが表示されるVBAにしてください。
A1のセルにタイマーのタイムアップ時刻を15:30(午後3時30分のとき)のように与えます。
タイマーは、タイムアップまでの残り時間を赤い色で塗って表示。
秒ごとに更新。
タイマーの時、分、秒は、時刻と同じデザインで時刻の下に1行の間隔をあけて表示。
--------------------------
Option Explicit
Dim StopFlag As Boolean
Sub DisplayClock()
Dim CurrentTime As Date
Dim CurrentHour As Integer
:
:
※前述の時計表示のVBAのコードを貼りつけてある。
正直なところ、これは出てきたコードを実行してもすぐには動かなかった。タイマーの値が正しく表示されなかったり、24時をまたぐ場合の処理が適切でなかったり。何回かのやりとりのあと、最終的にコードを見直して指示を与えることもして、ようやく動かすことができた。「タイマーとは」と丁寧に説明すべきところだった(前回記事の「空き時間とは」参照)。
このやり方の変形として、複雑なプログラムを作りたいときに、「このプログラムから呼び出されることを想定して関数のコードを書いてください」ということもできる。
ChatGPTが、コードを理解しているように見えるというのは凄いことだ。プロンプトではすべてを言葉で表現しなければならないという限界をあっさりと超えてしまうからだ。これは、かつて第四世代言語などといわれた時代のコードジェネレーターとは隔世の感がある。
こうしてできたエクセルのVBAで動く時計&タイマーを、以下に示す。A1のセルにタイムアップの時間を入力して実行。A1が空のときはただの時計となる。
プログラミングは《対話》によって行われることになった
プログラムの複雑さが増すにしたがってプロンプトも長くややこしいものとなり、ChatGPTとの間にも誤解が生じがちだ。そこで、OpenAIのテクニカルレポートにも書かれていることだが《few-shot prompt》という技を使う。つまり、いちどに完成形のコードを求めるのではなく、段階的に理解をうながしながら作り上げる。
同じくテクニカルレポートに出てくる「幻覚」(ハルシネーション=でっちあげ)は、コード生成でも出てくる。これは、単なるコーディングミス(関数と変数、型の定義の間違いなど)やゴールに対する誤解によって生ずるように見える。
前回記事でも書いたとおり実行時に出たエラーをそのままChatGPTに返してやって修正してもらうことができる。もちろん、間違っている点が明確であれば「〇〇ではなく××です」と指摘すればよい。そうやって、段階ごとに動きコードを導いて、次の段階に進めていくわけだ。
こうなると本当に、ChatGPTと一緒にプログラムを書いている気分になってくる。
なお、ここで「OpenAIのテクニカルレポート」と呼んでいるのは、3月27日に発表された"GPT-4 Technical Report"のことである。内容は多岐にわたっており、ChatGPTで何かをしようという人は一度は目を通しておくべき内容である。これについては、2017年頃から深層学習のセミナーをご一緒させていただいた丸山不二夫さんによる「GPT-4 Technical Report を読む」が参考になる。
プロンプトプログラミングの良い点、気になる点
プロンプトプログラミングについて、以下のようにまとめてみた。
プロンプトプログラミングの良い点
1)時間がかからない(書いてもらえる)
2)解説付き、コメント付きでコードが出てくるので、学びになる
3)テストデータを生成もできる
4)コードの品質の属人的なバラつきをなくすことができるかもしれない
一方、まだ課題も多いのでその点もまとめておく。
プロンプトプログラミングのダメなところ
1)プロンプトのノウハウが発展段階
2)大規模開発の手法が確立されていない
3)対話を続けると混乱に陥ることがある
4)検証しないとバグの温床になる(ただの生成ツールと考えよ)
前回記事でも指摘したように、やりとりを繰り返しているとChatGPTが混乱状態に陥ることがある。その場合には、同じセッションでは使えるようなコードには到達できないので、新たにセッションを始めたほうがよい。
最後の「検証しないとバグの温床になる」は、前向きにとらえれば、まだ人間のやることが残っているという意味でもある。ChatGPTは、あくまでプログラマがラクするための道具であって、その生成されたコードを人間が管理しながら使うというのが、まともなシステム開発では適切な付き合い方なのだろう。
ということで、なにぶん発展段階にあるChatGPTによるコード生成のお話なので、決定的な誤解もあるかもしれない。最後に、今回生成したエクセルで時計を表示するVBAのコード、タイマー付きバージョンを以下に紹介しておく。
VBAの実行方法については、すぐにできるので各自調べていただきたい。A1のセルに「15:20」などと入れて実行するとその時間までのタイマーも表示される。終了は、Ctrl-Breakやウィンドウを閉じる、タスクの終了などで行う。
Option Explicit
Dim StopFlag As Boolean
Dim TimerFlag As Boolean
Dim Pattern_num(0 To 9) As String
Dim Pattern As String
Dim TargetTime As Date
Dim i As Integer
Dim j As Integer
Sub DisplayClockAndTimer()
Dim CurrentTime As Date
Dim CurrentHour As Integer
Dim CurrentMinute As Integer
Dim CurrentSecond As Integer
Dim RemainingTime As Date
Dim RemainingHour As Integer
Dim RemainingMinute As Integer
Dim RemainingSecond As Integer
' Initialize StopFlag
StopFlag = False
' Initialize TimerFlag
TimerFlag = True
If Range("A1").Value = "" Then
TimerFlag = False
Else
' Get target time from A1
TargetTime = Range("A1").Value + Date
If TargetTime <= Now Then
TargetTime = DateAdd("d", 1, TargetTime)
End If
End If
' Clear cells
Range("A1:AA35").Interior.Color = RGB(255, 255, 255)
' Set Column Widths and Height
Range("A:AA").EntireColumn.ColumnWidth = 6
Range("1:35").EntireRow.RowHeight = 16
Do While Not StopFlag
' Get current time
CurrentTime = Now
CurrentHour = Hour(CurrentTime)
CurrentMinute = Minute(CurrentTime)
CurrentSecond = Second(CurrentTime)
' Display current time (Black)
DisplayNumber Range("A1"), CurrentHour \ 10, False
DisplayNumber Range("E1"), CurrentHour Mod 10, False
DisplayColon Range("I1"), False
DisplayNumber Range("K1"), CurrentMinute \ 10, False
DisplayNumber Range("O1"), CurrentMinute Mod 10, False
DisplayColon Range("S1"), False
DisplayNumber Range("U1"), CurrentSecond \ 10, False
DisplayNumber Range("Y1"), CurrentSecond Mod 10, False
If TimerFlag = True Then
' Calculate remaining time
If TargetTime >= CurrentTime Then
RemainingTime = TargetTime - CurrentTime
RemainingHour = Hour(RemainingTime)
RemainingMinute = Minute(RemainingTime)
RemainingSecond = Second(RemainingTime)
Else
RemainingTime = 0
RemainingHour = 0
RemainingMinute = 0
RemainingSecond = 0
End If
' Display remaining time (Red)
DisplayNumber Range("A19"), RemainingHour \ 10, True
DisplayNumber Range("E19"), RemainingHour Mod 10, True
DisplayColon Range("I19"), True
DisplayNumber Range("K19"), RemainingMinute \ 10, True
DisplayNumber Range("O19"), RemainingMinute Mod 10, True
DisplayColon Range("S19"), True
DisplayNumber Range("U19"), RemainingSecond \ 10, True
DisplayNumber Range("Y19"), RemainingSecond Mod 10, True
End If
' Wait 1 second
WaitSecond
' Allow other events
DoEvents
Loop
End Sub
Sub StopTimer()
' Set StopFlag to true to stop the timer
StopFlag = True
End Sub
Sub DisplayNumber(TopLeftCell As Range, Number As Integer, IsTimer As Boolean)
' Define patterns for numbers
Pattern_num(0) = "111" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"111"
Pattern_num(1) = "11 "& _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
"111"
Pattern_num(2) = "11 " & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"111"
Pattern_num(3) = "111" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
"11 " & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
"111"
Pattern_num(4) = "1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 1" & _
"1 1" & _
"111" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1"
Pattern_num(5) = "111" & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"111" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
"11 "
Pattern_num(6) = " 11" & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"1 " & _
"111" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"111"
Pattern_num(7) = "111" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 " & _
" 1 "
Pattern_num(8) = "111" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
" 1 " & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"111"
Pattern_num(9) = "111" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"1 1" & _
"111" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
" 1" & _
"11 "
' Display number
For i = 1 To 16
For j = 1 To 3
If Mid(Pattern_num(Number), (i - 1) * 3 + j, 1) = "1" Then
If IsTimer Then
TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 0, 0)
Else
TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(0, 0, 0)
End If
Else
TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 255, 255)
End If
Next j
Next i
End Sub
Sub DisplayColon(TopLeftCell As Range, IsTimer As Boolean)
' Define patterns for colon
Pattern = " " & _
" " & _
" " & _
" " & _
"1" & _
"1" & _
" " & _
" " & _
" " & _
"1" & _
"1" & _
" " & _
" " & _
" " & _
" " & _
" "
' Display colon
For i = 1 To 16
For j = 1 To 1
If Mid(Pattern, (i - 1) * 1 + j, 1) = "1" Then
If IsTimer Then
TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 0, 0)
Else
TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(0, 0, 0)
End If
Else
TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 255, 255)
End If
Next j
Next i
End Sub
Sub WaitSecond()
' Wait for 1 second
Application.Wait (Now + TimeValue("0:00:01"))
End Sub
遠藤諭(えんどうさとし)
株式会社角川アスキー総合研究所 主席研究員。MITテクノロジーレビュー日本版 アドバイザー。プログラマを経て1985年に株式会社アスキー入社。月刊アスキー編集長、株式会社アスキー取締役などを経て、2013年より現職。人工知能は、アスキー入社前の1980年代中盤、COBOLのバグを見つけるエキスパートシステム開発に関わりそうになったが、Prologの研修を終えたところで別プロジェクトに異動。「AMSCLS」(LHAで全面的に使われている)や「親指ぴゅん」(親指シフトキーボードエミュレーター)などフリーソフトウェアの作者でもある。趣味は、カレーと錯視と文具作り。2018、2019年に日本基礎心理学会の「錯視・錯聴コンテスト」で2年連続入賞。その錯視を利用したアニメーションフローティングペンを作っている。著書に、『計算機屋かく戦えり』(アスキー)、『頭のいい人が変えた10の世界 NHK ITホワイトボックス』(共著、講談社)など。
Twitter:@hortense667週刊アスキーの最新情報を購読しよう
本記事はアフィリエイトプログラムによる収益を得ている場合があります