注意: AI を使ったプログラミングのために、最低限の基本概念を説明したい。理解のために正確性が伴っていない箇所がある。
tl;dr
- プログラミングは「コンピュータに指示を出す方法」であり、プログラミング言語はその指示を書くための言語
- プログラムはデータの流れを表すグラフ構造として捉えると理解しやすい
- データ構造(特にJSON)を理解すると、AIとの対話が効率的になる
- プログラミングの本質は「問題を小さく分解して解決する」という考え方
- チューリング完全な言語であれば、理論上どんな計算でも表現できる
そもそもプログラミングとは
プログラミングとは、コンピュータに指示を与えることです。
コンピュータは融通が効きません。曖昧性を廃した、厳密な命令を送り込む必要があります。「なんかいい感じにしてよ」の対極がプログラミング言語です。ただ指示を与えるだけでは、複雑な処理はできません。
この理解のために、プログラミング言語の厳密性、チューリング完全、グラフ、データ構造という概念を説明します。
自然言語とプログラミング言語の違い
人間の言語(日本語や英語など)は曖昧さや文脈依存性があり、同じ言葉でも状況によって意味が変わることがあります。一方、プログラミング言語は曖昧さを排除し、明確なルールに従って記述します。
例えば、「りんごを食べる」という日本語の文は、状況によって解釈が変わる可能性がありますが、プログラミング言語では以下のように明確に記述します:
eat(apple);
これは「eat」という動作を「apple」というオブジェクトに対して行うという指示です。プログラミング言語では、このような明確な構文(シンタックス)に従って記述する必要があります。
チューリング完全とは
プログラミングの概念を理解する上で、チューリング完全という言葉を知っておくと良いでしょう。
チューリング完全とは、ある計算モデルが、チューリングマシンと呼ばれる仮想的な計算機と同じ計算能力を持つことを意味します。
すごく簡単に言うと、チューリング完全な計算モデルは、私たちが普段使っているコンピュータでできることと同じことができる、ということです。
多くのプログラミング言語はチューリング完全です。例えば、JavaScript、Python、C++などはすべてチューリング完全な言語です。これらの言語を使うことで、理論上はどんな計算でも表現できます。つまり、チューリング完全な言語を使えば、どんな複雑なプログラムでも作ることができる、ということです。
AIプログラミング視点: 自然言語とハルシネーション
自然言語は、その曖昧さから、AIが指示を理解する際に「ハルシネーション(幻覚)」を引き起こすことがあります。これは、言葉の解釈が一意に定まらず、AIが意図しない解釈をしてしまう現象です。
例えば、「赤いりんご」という言葉は、AIにとって「色」と「果物」という2つの属性を持つオブジェクトを指し示すことになりますが、その解釈は文脈によって変わる可能性があります。
プログラミング言語は、このような曖昧さを排除し、明確な構文(シンタックス)に従って記述します。そのため、AIはプログラミング言語の指示をより正確に理解し、意図した通りのコードを生成することができます。
逆に言うと、その要求に応える概念モデルを人間が持たなければなりません。
プログラミングはグラフ構造の管理
プログラミングの本質を理解するために重要な概念として、「プログラムはグラフ構造である」ということを説明します。
おおっと、まだ立ち去らないでください。これ自体は難しい概念ではありません。
テキストで記述されるプログラミング言語はパーサという仕組みで、抽象構文木というデータに組み立てられます。
抽象構造木は、階層的な関係を表すのに適したデータ構造です。例えば、フォルダ構造などが木構造で表現できます。
ある命令は、他のファイルに書かれた命令を呼び出したりします。これによって、ある抽象構文機が、意味的には木のノードに向いていることを意味し、これによってグラフを構築します。
グラフ構造は、より複雑な関係を表すのに適したデータ構造です。例えば、SNSの友達関係や道路のネットワークなどがグラフ構造で表現できます。
テキストで書かれたコードは、このグラフを圧縮して記述していると言えます。
AIを使ったプログラミングで必要なのは、このグラフ構造の理解が重要になります。
もっと詳しく: グラフ構造とは
グラフ構造とは、「ノード(節点)」と「エッジ(辺)」からなるデータ構造のことです。プログラムでは:
- ノード: 変数、関数、オブジェクトなどのデータや処理の単位
- エッジ: ノード間の関係性や依存関係
例えば、以下のようなJavaScriptのコードを見てみましょう:
function 挨拶(名前) {
return "こんにちは、" + 名前 + "さん!";
}
const メッセージ = 挨拶("太郎");
console.log(メッセージ);
このコードは以下のようなグラフ構造として表現できます:
[挨拶関数] ---> [メッセージ変数] ---> [console.log]
^
|
["太郎"(引数)]
このように、プログラムは「データの流れ」として捉えることができます。AIにプログラムを生成してもらう際も、この「データがどう流れるか」という視点で考えると理解しやすくなります。
実際のプログラムの流れ
プログラムは、先に説明したグラフ構造を辿って実行されます。
グラフをたどる経路は、一方向であるとはあるとは限りません。繰り返しや条件分岐によって、何度も同じ場所をグラフを通る可能性があります。
もう少し複雑な例を見てみましょう。ユーザーの入力を受け取って計算するプログラムの流れは以下のようになります:
[ユーザー入力] ---> [入力検証] ---> [計算処理] ---> [結果表示]
|
v
[エラー処理]
このように、プログラムは「入力」から始まり、様々な処理を経て「出力」に至る一連の流れとして捉えることができます。AIにプログラムを生成してもらう際も、「入力は何か」「どのような処理が必要か」「出力はどうあるべきか」を明確に伝えることが重要です。
データ構造 (JSON)
プログラミングでは、データをどのように構造化するかが重要です。最も一般的なデータ構造の一つが「JSON(JavaScript Object Notation)」です。
JSONとは
JSONは以下のような特徴を持ちます:
- 人間にも読みやすい形式
- キーと値のペアでデータを表現
- 階層構造を表現できる
- 多くのプログラミング言語でサポートされている
例えば、人物の情報をJSONで表現すると:
{
"名前": "山田太郎",
"年齢": 30,
"住所": {
"都道府県": "東京都",
"市区町村": "渋谷区"
},
"趣味": ["読書", "映画鑑賞", "プログラミング"]
}
このようにデータを構造化することで、コンピュータはデータを効率的に処理できます。AIにプログラムを生成してもらう際も、「どのようなデータ構造が必要か」を考えることが重要です。
JSONのデータ型
JSONには以下のような基本的なデータ型があります:
-
文字列(String): テキストデータ(例:
"こんにちは","山田太郎") -
数値(Number): 数値データ(例:
42,3.14) -
真偽値(Boolean):
trueまたはfalse -
配列(Array): 複数の値をまとめたもの(例:
[1, 2, 3],["りんご", "バナナ", "オレンジ"]) -
オブジェクト(Object): キーと値のペアの集まり(例:
{"名前": "太郎", "年齢": 30}) - null: 値が存在しないことを表す
これらの基本的なデータ型を組み合わせることで、複雑なデータ構造を表現できます。
JSON はおそらく最も普及しているデータ構造の一つです。言語が違っても、このJSONで伝えれば基本的に理解可能です。
JSONですべてのデータを表せるわけではありません。条件分岐や、JSON内の別のデータを参照することは、特殊なツールを使わない限りは不可能です。
プログラミングの基本概念
プログラミングの基本的な概念を説明します。
これは、汎用的なプログラミングならある程度共通します。
変数と定数
変数とは、データを一時的に保存するための「箱」のようなものです。
例えば JavaScriptでは、letやconstを使って変数を宣言します:
// 変数(後から値を変更できる)
let 年齢 = 30;
年齢 = 31; // 値を変更できる
// 定数(一度設定したら変更できない)
const 名前 = "山田太郎";
// 名前 = "鈴木次郎"; // エラー:定数は変更できない
条件分岐
条件に応じて処理を分岐させるには、if文を使います:
const 年齢 = 18;
if (年齢 >= 20) {
console.log("成人です");
} else if (年齢 >= 18) {
console.log("18歳以上ですが、20歳未満です");
} else {
console.log("未成年です");
}
これがあるおかげで、一度も実行したことがない組み合わせに対しても対応ができます。
条件分岐をイメージするには、今目の前にない状況や概念に対する抽象思考が必要になります。
繰り返し処理
同じ処理を繰り返し行うには、for文やwhile文を使います。
JavaScriptの例です。
// for文の例
for (let i = 0; i < 5; i++) {
console.log(`${i}回目の繰り返し`);
}
// 配列の各要素に対する繰り返し
const 果物 = ["りんご", "バナナ", "オレンジ"];
for (const 項目 of 果物) {
console.log(項目);
}
関数
WIP: 自分が勉強したときのことを思い出すと、ここの説明はもっと頑張る必要がある。
関数とは、一連の処理をまとめたものです。関数を使うことで、同じ処理を何度も書く必要がなくなります:
// 関数の定義
function 挨拶(名前) {
return `こんにちは、${名前}さん!`;
}
// 関数の呼び出し
const メッセージ = 挨拶("太郎");
console.log(メッセージ); // "こんにちは、太郎さん!"と表示される
AIとプログラミングの関係
AIを使ってプログラミングする際、上記の基本概念を理解していると、AIとの対話がより効果的になります。
AIに伝えるべき情報
AIにプログラムを生成してもらう際、以下の情報を明確に伝えると良いでしょう:
- 目的: 何を実現したいのか
- 入力: どのようなデータを扱うのか
- 処理: どのような処理を行いたいのか
- 出力: どのような結果を得たいのか
- 制約: 特定の技術や方法を使いたいか
例えば、「ユーザーが入力した2つの数値を足し算して表示するプログラムを作りたい。HTMLとJavaScriptを使って実装してほしい。」というように具体的に伝えると、AIはより適切なコードを生成できます。
AIが生成したコードの理解
AIが生成したコードを理解するためには、上記の基本概念を知っておくことが重要です。コードを見たときに、「このコードは何をしているのか」「データはどのように流れているのか」を考えることで、AIとの協業がより効果的になります。
プログラミング的思考
プログラミングの本質は、「問題を小さく分解して解決する」という考え方です。これは「プログラミング的思考」と呼ばれ、プログラミング以外の場面でも役立つスキルです。
問題の分解
大きな問題を小さな問題に分解することで、複雑な問題も解決できるようになります。例えば、「オンラインショッピングサイトを作る」という大きな問題は、以下のように分解できます:
- ユーザー登録・ログイン機能
- 商品一覧表示機能
- 商品詳細表示機能
- カート機能
- 決済機能
- 注文履歴表示機能
このように問題を分解することで、一つ一つ解決していくことができます。
アルゴリズム的思考
アルゴリズムとは、問題を解決するための手順のことです。例えば、「料理のレシピ」もアルゴリズムの一種と言えます。プログラミングでは、問題を解決するための効率的なアルゴリズムを考えることが重要です。
例えば、「1から100までの数字の中から偶数だけを表示する」というアルゴリズムは以下のように考えることができます:
- 変数
iを2から始める -
iが100以下の間、以下を繰り返す
a.iを表示する
b.iに2を足す
このアルゴリズムをJavaScriptで実装すると:
for (let i = 2; i <= 100; i += 2) {
console.log(i);
}
このように、問題を解決するための手順を明確に考えることが、プログラミングの基本です。
まとめ
プログラミングの基本概念を理解することで、AIとの対話がより効果的になり、思い通りのプログラムを作れるようになります。特に重要なポイントは:
- プログラミング言語は「コンピュータへの指示」を書くための言語
- プログラムは「データの流れ」として捉えると理解しやすい
- データ構造(特にJSON)を理解すると、データの扱いが明確になる
- プログラミング的思考(問題の分解、アルゴリズム的思考)は様々な場面で役立つ
- チューリング完全な言語であれば、理論上どんな計算でも表現できる