ソフトウェア

GPT-4で新しいプログラミング言語「TenetLang」を生み出す、チャットAIは既にプログラミングの何たるかをかなり理解している模様


OpenAIが作成したチャットAIの「GPT-4」を利用して、新しいプログラミング言語の「TenetLang」をコーダーのルークさんが作成しています。

GPT-4 Designed a Programming Language
https://lukebechtel.com/blog/gpt4-generating-code

GPT-4のような大規模言語モデル(LLM)は、世界中に存在するあらゆるプログラミング言語を何十億回も読み込んでいます。LLMはプログラミングも可能であることは知られていますが、ルークさんは「私の知る限り、GPT-4で独自のプログラミング言語を作成するといった事例はこれまでありません」と記しています。そこで、ルークさんはGPT-4を使って新しいプログラミング言語を創造することに決めた模様。

ルークさんは最初にGPT-4に対して「ソフトウェア開発における大まかな統一理論を提案するとしたら、どんなものになりますか?」と質問します。その結果返ってきた回答は「ソフトウェア開発における統一理論を提案するのは困難ですが、高品質なソフトウェアを開発するための包括的なガイドとして役立つ10個の重要な原則なら提案できます」とし、以下の10個の原則を提案しました。

1:モジュール性
ソフトウェアを自己完結型の再利用可能な小さなコンポーネントに分割することで、開発、保守、理解を簡素化すること。

2:抽象化
明確に定義されたインターフェースを提供して懸念事項を分離することで、システムの複雑さを隠し、開発者が詳細に圧倒されることなく特定の領域に集中できるようにすること。

3:スケーラビリティ
必要に応じて効率的にスケーリングできる機能を備えた幅広いワークロードと要求を処理するソフトウェアを設計すること。

4:保守性
保守、更新、コラボレーションを容易にするために、クリーンでわかりやすく、十分に文書化されたコードを記述すること。

5:テスト容易性
単体テスト、統合テスト、システムテストを含む包括的なテスト戦略を策定し、ソフトウェアの堅牢性と信頼性を確保すること。

6:適応性
要件、テクノロジー、ユーザーニーズの更新など、将来の変更に対応できる柔軟性を備えたソフトウェアを設計すること。

7:パフォーマンス
機能性や保守性を損なうことなくソフトウェアを最適化して効率的に実行することで、リソースの使用を最小限に抑え、応答時間を最大化すること。

8:セキュリティ
強力なセキュリティ対策を実装して、ソフトウェアとユーザーデータを不正アクセス、誤用、脆弱性から保護すること。

9:コラボレーション
開発者、テスター、デザイナーおよびその他の利害関係者の間で効果的なコミュニケーションとチームワークを促進し、プロジェクトの目標、要件、進行状況を共有して理解できるようにすること。

10:継続的な改善
継続的な学習、評価、反復開発の文化を受け入れ、ソフトウェアと開発プロセスを時間の経過とともに改善し、新しい手法やテクノロジーおよびベストプラクティスに適応させること。


さらに、ルークさんが「上記の10個の原則が上手く機能するケースと困難になるケースの事例を挙げてください」と質問すると、GPT-4は以下のように出力しています。

1:モジュール性
上手く機能するケース:
1つのタスク(grep、sed、awkなど)を適切に実行し、組み合わせて複雑なパイプラインを作成できるという、UNIXの哲学。

困難なケース:
既存の機能を壊さずにリファクタリングや新機能の導入をすることが困難な、コンポーネントが密結合した大規模なレガシーシステム。

2:抽象化
上手く機能するケース:
オブジェクト指向のプログラミング言語(Java、C++など)は、カプセル化を促進し、明確に定義されたインターフェイスの背後に実装の詳細を隠します。

困難なケース:
抽象化を過度に行うと、過剰なエンジニアリングにつながり、コードが必要以上に複雑になる可能性があります。

3:スケーラビリティ
上手く機能するケース:
GoogleのMapReduceApache Kafkaなどの分散システム。水平方向にスケーリングして大量のデータとユーザーに対応することができます。

困難なケース:
スケーラビリティを考慮して設計されていない場合、モノリシックアーキテクチャとなってしまうため、大幅なリファクタリングを行わないと増加したワークロードを処理することが困難になります。

4:保守性
上手く機能するケース:
LinuxやPythonなどのオープンソースプロジェクトでは、コラボレーションと長期的なメンテナンスを容易にするためのコーディング標準とベストプラクティスが確立されています。

困難なケース:
不十分なドキュメンテーションまたは一貫性のないコーディングスタイルを備えた独自のコードベースが、コードの理解と維持を困難にします。

5:テスト容易性
上手く機能するケース:
コードを実装する前にテストを作成することを重視するテスト駆動開発(TDD)方法論。これにより、完全なテストカバレッジとより信頼性の高いソフトウェアが保証されます。

困難なケース:
多くの依存関係や副作用を伴う複雑なシステムは、テストのためにコンポーネントを分離することが難しくなります。

6:適応性
上手く機能するケース:
システム全体に影響を与えることなく個々のサービスを個別に更新、スケーリング、置換できるマイクロサービスアーキテクチャ。

困難なケース:
オープンあるいはクローズドの原則に従わない、厳格で柔軟性のないコード。新しい機能の導入や変化する要件への適応を困難にします。

7:パフォーマンス
上手く機能するケース:
ハイ・パフォーマンス・コンピューティング(HPC)システム。パフォーマンスが重要であり、開発者は専用のハードウェアで効率的に実行できるようにコードを最適化しているため。

困難なケース:
コードの可読性と保守性を犠牲にしてパフォーマンスをわずかに向上させるような、時期尚早な最適化。

8:セキュリティ
上手く機能するケース:
開発者が一般的なセキュリティの脆弱性を回避するのに役立つ、OWASP Top 10などの安全なソフトウェア開発プラクティス。

困難なケース:
セキュリティへの十分な注意が払われていない場合、脆弱性を簡単に悪用できるソフトウェアや既知のセキュリティ上の欠陥がある古いテクノロジーへの依存につながります。

9:コラボレーション
上手く機能するケース:
チームワーク、コミュニケーション、反復開発を重視するスクラムかんばんなどのアジャイルソフトウェア開発

困難なケース:
チームが分断された状態で効果的なコミュニケーションを行わずにサイロで作業すること。誤解、重複した作業、遅延などの発生原因となります。

10:継続的な改善
上手く機能するケース:
DevOpsプラクティス。開発チームと運用チームの統合を促進し、継続的な学習と改善の文化を育みます。

困難なケース:
変化に抵抗する組織や、学習と実験の文化を欠いている組織は、新しい技術、テクノロジー、ベストプラクティスの採用を困難にします。


続けて、ルークさんは「これらのアイデアを含む新しいプログラミング言語を設計する場合、どのようなものになりますか?」とGPT-4に問いかけます。すると、「優れたソフトウェア開発の原則をすべて網羅する新しいプログラミング言語を設計することは複雑な作業です。1回の回答ですべての詳細をカバーすることはできません。ただし、上記のアイデアを考慮していくつかの機能および設計上の選択肢となるような概要を示すことはできます」とGPT-4は出力。

GPT-4が出力した、上記のアイデアをなるべく網羅したプログラミング言語の概要は以下の通り。

1:シンプルさと読みやすさを重視
構文は明確かつ簡潔で、理解しやすいものにする必要があります。Pythonはインデントと単純な構文を使用して読みやすさを強調するプログラミング言語の好例です。

2:複数のプログラミングパラダイムをサポート
オブジェクト指向、関数型プログラミング手続き型プログラミングなど、タスクに最適なパラダイムの使用を奨励します。これにより、開発者はニーズに最適なアプローチを柔軟に選択できるようになります。

3:強力な型付けと型推論
強力な型システムは、エラーを早期に検出してコードの安全性を向上させるのに役立ち、型推論は冗長性を減らし、読みやすさを向上させます。TypeScriptHaskellなどのプログラミング言語は、強力な型付けと型推論のバランスが取れた好例です。

4:第一級関数クロージャー
第一級関数とクロージャーをサポートすると、JavaScript、Scala、Kotlinなどのプログラミング言語で見られるような、強力な関数型プログラミング手法が可能になります。

5:不変のデータ構造
不変のデータ構造の使用を奨励し、意図しない副作用のリスクを最小限に抑えることで、コードについての推論が容易になります。

6:同時実行と並列処理の組み込みサポート
JavaScriptのAsync/awaitやGoのGoroutine、Erlangのアクターなどは、同時実行と並列実行を管理するための言語レベルの構成要素を提供します。

7:拡張可能なモジュラー構文
開発者はLISPのマクロやScalaの暗黙関数に見られるように、コア言語とシームレスに統合できるカスタム構文、DSL、ライブラリを開発者が作成できるようにします。

8:統合されたセキュリティ機能
プログラミング言語の設計の一部に、セキュリティ機能とベストプラクティスを含めます。例えば、自動メモリ管理境界チェックなど、バッファオーバーフローなどの一般的な脆弱性を防止します。

9:ガベージ コレクションとメモリの安全性
Java、C#、Rustなどのプログラミング言語で見られるように、メモリ管理を自動化してメモリリークを防ぎ、メモリの安全性を高めること。

10:他のプログラミング言語との相互運用性
他のプログラミング言語から関数を呼び出したり、ライブラリを使用したりするための組み込みサポートを提供することで、既存のコードとのコラボレーションおよび再利用を促進します。

なお、上記の10個のアイデアについて、GPT-4は「トレードオフなしでこれらすべての側面をカバーする完璧なプログラミング言語を作成することは不可能ですが、これらのアイデアを組み込むことは、優れたソフトウェア開発を促進するプログラミング言語を作成する役に立ちます」と記しています。


ここまでさまざまなアイデアを提案してきたGPT-4は、これらを順守するプログラミング言語を「TenetLang」と名付け、さらなる詳細を提案しています。TenetLangはPythonに着想を得た単純な構文と、関数型およびオブジェクト指向のプログラミング言語のいくつかの機能を組み合わせたプログラミング言語になるとのこと。さらに、GPT-4はTenetLangの設計における8つの概要を以下の通り示しました。

1:Pythonに似たインデントベースのスコープ
2:TypeScriptとKotlinに触発された、型推論による強力な型付け。
3:JavaScriptに似たファーストクラスの関数とクロージャー。
4:デフォルトでは不変のデータ構造であり、オプションで可変に対応。
5:無名関数の簡潔なラムダ構文
6:HaskellとRustに触発された、パターンマッチングとデストラクチャリング。
7:Async/awaitおよび軽量スレッドを使用した同時実行の組み込みサポート。
8:FFIを使用した他のプログラミング言語との相互運用性。

以下は、GPT-4が出力した「TenetLangの構文と機能を示すプログラムの簡単な事例」です。

class Person {
    let name: String
    let age: Int

    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }

    toString() -> String {
        return f"{this.name} ({this.age})"
    }
}

async function fetchPersons() -> List[Person] {
    // Simulate an asynchronous fetch operation using lightweight threads
    await sleep(1000)
    return [
        Person("Alice", 32),
        Person("Bob", 28),
        Person("Carol", 35),
        Person("Dave", 23)
    ]
}

function filterAdults(persons: List[Person]) -> List[Person] {
    return persons.filter(p => p.age >= 18)
}

function sortByName(persons: List[Person]) -> List[Person] {
    return persons.sortBy(p => p.name)
}

async function main() {
    let persons = await fetchPersons()
    let adults = filterAdults(persons)
    let sortedAdults = sortByName(adults)

    for person in sortedAdults {
        print(person)
    }
}

main()


上記のプログラム事例は「シンプルさと読みやすさ」「複数のプログラミングパラダイム」「強力な型指定と型推論」「不変のデータ構造」「同時実行性」「相互運用性」といった、GPT-4が提案した新しいプログラミング言語のための複数の基準を満たしています。ルークさんは出力されたTenetLangのコード事例を見て、「基本的に、TenetLangはTypescriptとPythonの赤ちゃんのようです」と記しました。


ルークさんは分散コンピューティングがカバーされていないことに気づいたため、「このプログラミング言語を分散コンピューティングに役立つよう改善することはできますか?」とGPT-4に依頼。

すると、GPT-4は「ここまでのTenetLangの事例は、主に単一プロセス内の同時実行性に焦点を当てたものであるため、分散コンピューティングを明示的に扱っていません。TenetLangを改善して分散コンピューティングをより適切にサポートするには、分散コンポーネント間の通信と調整を容易にする機能を導入する必要があります」と出力。


そのためのアイデアが以下の5つです。

1:メッセージパッシングと軽量アクター
組み込みのメッセージパッシングメカニズムと軽量アクター(ErlangまたはAkkaに触発されたもの)を組み込むことで、分散コンポーネント間の非同期ノンブロッキング通信が可能になります。

2:リモートプロシージャコール(RPC)
RPCのサポートを統合することで、異なるマシンまたは異なるプログラミング言語で実行されているサービス間の通信を実現します。これはgRPCやApache Thriftなどの一般的なRPCプロトコル用の組み込みライブラリまたはフレームワークを提供することで実現できます。

3:シリアライゼーションとデシリアライゼーション
データの効率的なシリアライゼーションとデシリアライゼーションのサポートを含む、分散コンポーネント間での複雑なデータ構造を簡単に送信できるようにします。JSON、BSON、プロトコルバッファなどの一般的な形式のサポートを組み込むことを検討してください。

4:分散データ構造
分散ハッシュテーブル(DHT)や分散データベースなど、複数のノード間で共有および操作できる分散データ構造の組み込みサポートを提供。

5:フォールトトレランス
監視ツリー、自動再試行、タイムアウトのサポートなど、フォールトトレランスを促進する機能を統合することで、回復力のある分散システムの構築が容易になります。

上記のアイデアを取り入れた改良版TenetLangを用いた「構文および機能を示すプログラムの簡単な事例」が以下。

import actors
import rpc

class Person {
    // Same as before...
}

// RPC service definition for a remote data source
service PersonService {
    rpc fetchPersons() -> List[Person]
}

actor PersonFetcher {
    let service: PersonService

    constructor(service: PersonService) {
        this.service = service
    }

    receive(msg) {
        case FetchPersons => {
            let persons = this.service.fetchPersons()
            reply(persons)
        }
    }
}

function filterAdults(persons: List[Person]) -> List[Person] {
    // Same as before...
}

function sortByName(persons: List[Person]) -> List[Person] {
    // Same as before...
}

async function main() {
    // Connect to a remote PersonService
    let personService = rpc.connect(PersonService, "http://example.com/person-service")

    // Create a PersonFetcher actor
    let fetcher = PersonFetcher(personService)

    // Send a FetchPersons message to the fetcher and await the
        let persons = await fetcher.send(FetchPersons)
    let adults = filterAdults(persons)
    let sortedAdults = sortByName(adults)

    for person in sortedAdults {
        print(person)
    }
}

main()


さらに、ルークさんはGPT-3やChatGPTのようなLLMを簡単に組み込むことができる新しい機能をTenetLangに追加することを提案。すると、GPT-4はチャットAIモデルとやり取りするためのシンプルで便利なインターフェイスを提供するための組み込みライブラリの導入を提案しました。このライブラリは、APIリクエスト、認証、データのシリアル化/逆シリアル化といった複雑な処理を担当してくれるそうです。

ただし、このライブラリはLLMとやり取りするための単純なインターフェイスを提供することに重点を置いたものであるため、より深い統合を行うには何ができるかをルークさんは尋ねています。すると、GPT-4はコーディング中に開発者がAIモデルの機能を利用してプログラミングの役に立てることができるようにすべきと提案。そこで、GPT-4は「プログラミング言語自体にLLMを搭載することで『スマートな提案』を行う機能を実装すること」を提案しています。これにより、開発者のコードを補完し、リファクタリングの提案を行うことなどが可能になるそうです。

ルークさんがGPT-4と対話しながら作成したプログラミング言語のTenetLangは、GitHub上で公開されています。

GitHub - tenetlang/tenetlang: A GPT-Designed Language Built for Humans
https://github.com/tenetlang/tenetlang

この記事のタイトルとURLをコピーする

・関連記事
AIを作るAIを作る - GIGAZINE

チャットAIのGPT-4でポケモンをプレイすることに成功、「勝利」と入力するだけでポケモンリーグ制覇 - GIGAZINE

画像生成AIの「Stable Diffusion」をゲームに活用する方法 - GIGAZINE

対話AI「ChatGPT」を使って未知の言語「スライム語」を発明するという試み - GIGAZINE

in ソフトウェア, Posted by logu_ii

You can read the machine translated English article here.