TL;DR
- Penという名前の新しいプログラミング言語を開発中
- スケーラブルなソフトウェア開発のための言語
- いいね、よろしくおねがいします!
導入
Pen言語という新しいプログラミング言語をGitHubでオープンソースで開発しています。アプリケーションプログラミングに焦点を置いていて、誰でも簡単に学習し、良いプログラムが書ける言語を目指しています。パラダイムとしては、関数型プログラミング寄りで、純粋ではありませんが独自の副作用を管理する仕組みがあります。
Hello, worldの例:
import System'Context { Context }
import System'File
sayHello = \(ctx Context) none | error {
File'Write(ctx, File'StdOut(), "Hello, world!\n")?
none
}
main = \(ctx Context) number {
e = sayHello(ctx)
if e = e as none {
0
} else if error {
1
}
}
目的
Pen言語の開発目的は、ソフトウェア開発をスケーラブルにすること、つまり、長期間、また、多人数によるソフトウェア開発を効率化することです。そのために、Pen言語はソフトウェアの性質の中でも保守性と移植性を重視した言語になっています。
- 保守性
- 最小設計の言語機能が、新しい開発者の学習コストを下げ、また、開発者間のコミュニケーションを効率化します。
- 関数における副作用の使用を制限することで、テストの容易性・信頼性を向上させます。
- アプリケーションと実装の詳細のコードを分けることで、それぞれのロジックの変更を容易にします。
- 移植性
- Pen言語で書かれたソフトウェアは異なるプラットフォームに容易に移植できます。
機能
小さな言語設計
これらの目的を達成するために、Pen言語は構文の表現力や実用性を保ちつつ、非常にミニマルで制限が強い言語として設計されています。既存のミニマルな言語設計がなされた例としてGo言語がありますが、それと比較してもとても小さいことが分かると思います。
型・構文
型システムは、静的型付けでサブタイピングがあります。しかし、言語の複雑さを抑えるためジェネリクスはありません。組み込みの型には、数値型、文字列型、リスト型、None型、レコード型、ユニオン型等があります。将来的に、配列型やマップ型の拡張を考えています。システムプログラミングではなく、アプリケーションプログラミングを主要な用途に考えているため、ビット数固定の整数型等は実装されていません。
構文には値リテラル、演算子、If式等があります。基本的に式指向で関数定義を含め、ほとんどが式として表現できます。ビルトインのいくつかの型(ユニオン、リスト等)にはそれらの値に対する独自の構文があります。
四則演算の例:
f = \() number {
1 + 2 - 3 * 4 / 5
}
型スイッチ(ダウンキャスト)の例:
f = \(x number | none) number {
if x = x as number {
x
} else if none {
0
}
}
システム注入
システム注入は、Pen言語独自の関数の副作用を管理する仕組みです。主に以下の2点の機能から成ります。
- 関数内における副作用の制限
- 関数の副作用は常にその引数から注入されます。これによりある関数が意図せずに非純粋になることを防ぎます。
- 慣習的にこれらの副作用を表現する値の型はコンテキスト型と呼ばれ、関数の先頭の引数として渡されます。
- システムパッケージ
- システム依存なコードはシステムパッケージという特別なパッケージによって提供されます。
- システムパッケージが提供するコンテキスト型を、アプリケーションのメイン関数に渡すことによって、初めてアプリケーションは副作用を起こすことができます。
システム注入によって開発者は、ソフトウェアのテスト容易性・信頼性、移植性の向上といった恩恵を受けられます。
ファイル書き込みの例:
import System'Context { Context }
import System'File
import System'File'OpenOptions
writeFile = \(ctx Context) none | error {
f = File'OpenWithOptions(
ctx,
"./foo.txt",
OpenOptions{...OpenOptions'Default(), Write: true},
)?
File'Write(ctx, f, "foo")?
none
}
main = \(ctx Context) number {
if _ = writeFile(ctx) as none {
0
} else {
1
}
}
決定的なテストフレームワーク
Pen言語には組み込みのテストフレームワークがあります。また、関数の副作用が制限されているため、全てのユニットテストが決定的です。これにより、コードの変更によって、テストが確率的に失敗したり、遅くなることがありません。
開発状況
最新版はv0.3.4で主要な言語機能は既に実装されています。現在は、非同期ランタイムの開発に注力しています。
既に実装されている機能
- 主要な言語構文
- 組み込み型(数値、文字列、リスト等)
- 参照カウントGC
- モジュール・パッケージシステム
- テストフレームワーク
- 標準パッケージ (
Os
,Core
) - クロスコンパイル
- 外部関数インターフェース
- WebAssembly/WASIターゲット
今後実装予定の機能
非同期ランタイム
一般に、プログラムが時間を消費する場合は大きく分けて2つ、CPUが計算をする、または、しない場合があります。このCPUが計算をしない場合の処理を別のスレッド等で非同期に処理することによって、プログラム全体の処理を効率化することができます。このような機能は主要な言語(JavaScript、Go、Rust等)で既に実装され、よく使われています。
Pen言語では同等の機能を実現するために、コンパイラ内で継続渡しスタイルという関数の内部表現を使っています。そして、これらの関数を状態マシンとしてスレッドプールで実行することで非同期ランタイムを実装します。現在、コンパイラ側の機能は既に実装されており、ランタイムライブラリ側を実装中です。
他言語との相互運用性の向上
Pen言語には既にOSとのインタフェースを担う標準パッケージが存在しています。しかし、そのAPIはとてもプリミティブでシステムコールに近いものです。そのため、その上にHTTPフレームワーク等を実装するのには非常に時間がかかります。
この労力を緩和するために、他言語(特にRust)の既存ライブラリの内、システムAPIを必要とするものを再利用できる仕組みを考えています。具体的には、前述したシステムパッケージを一つのアプリケーション内で複数使えるようにする予定です。これにより、例えば、OSパッケージ内のファイルシステムAPIとHTTPフレームワークパッケージ内のAPIが同時に使えます。ただし、これら複数のシステムパッケージが同じコンパイルターゲットをサポートしている必要があります。
その他
その他に以下の機能を実装予定です。
- 言語構文の細かな調整
- 標準パッケージのAPI拡張
- 並列・並行計算プリミティブの設計・実装
おまけ
- 開発に参加したいという方は是非ご連絡ください!
- プログラミング言語処理系が好きなひとの集まりというSlackで開発を行っています。興味のある方は是非ご参加ください!