純粋関数型システム言語Cargryを開発しています(自作クレートに納得がいかん)
なぜv2を?
前回記事にすでに用語集がありますが、その後Cargryに見つかった弱点の改善によって若干仕様が変わったからです
Cargryでは、Rustでは当たり前に書ける以下のコードと同等のものを表現できませんでした
struct Object {
value: String,
}
impl Object {
pub fn new(value: String) -> Self {
Self { value }
}
pub fn get_value(&self) -> &String {
&self.value
}
}
fn f() -> Object {
let s = String::from("Hello.");
let o = Object::new(s);
o
}
fn main() {
let o = f();
println!("{}", o.get_value());
}
表現できない理由
先ほどのコードのf関数を安直にCargryに直すと、以下のようになります
fun f() -> Object {
let s = String::from("Hello.");
let o = Object::new(s);
o
}
すると、3行目でエラーとなります
理由は簡単でCargryのメモリ管理モデルである、独占モデル故、ムーブができないのです
「じゃあ、参照を使えば?」とは簡単に言えません。構造体Objectが参照を持つ時、返り値にすることができません。ライフタイムが無いので、簡単に参照を返すわけにはいきません
このようなことがあったために、改訂する必要があり、この記事を書くことを決めました
用語
Cargry
カルグライ。また、綴りからそう読めると判断可能な読み方。Cargry言語そのものを指す
CrIR
クライア。クリア。また、綴りからそう読めると判断可能な読み方。Cargry言語のソースコードから、LLVM IR、またはCranelift IRを出力するまでの間に変換される中間表現。CrIRで、Cargryのルールを適用する
純粋スコープ
あるスコープが純粋である時、そのスコープを純粋スコープと言う
副作用スコープ
あるスコープ内で、副作用をハンドルする時、その副作用型内の関数のスコープを副作用スコープと言う
独占、独占状態
値を、参照を用いずに他の変数へ渡すことがない状態のこと。または、参照を、新しい参照を用いずに他の変数へ渡すことがない状態
独占者
参照ではない、値の独占状態にある変数のこと。全ての変数は独占者である
孤立
値を参照する参照の独占者が存在しない状態のこと
外出者
スコープの持つ値となる、値の独占者のこと
単独値
即値、または一時値のこと。独占者が存在しない値、または参照
破棄
値のメモリを解放すること。値の独占者に対して行う。必ず、スコープの終端で行われる
ルール
独占モデル
Cargryのメモリ管理の中心モデル
- いかなる値、または参照には対応する独占者が存在する
- 値が破棄されるまで、参照を取ることができる
- 値の作られたスコープの終端で、その値が破棄される
- 単独値はスコープを跨いで束縛することができる
- 初期化関数が単独値を受け取る時、その関数はインライン展開されなければならない
- ループ中に、ループを終了させたり、次のループに移ったりすることはできない
- 関数の返り値は必ずスコープの終端で返し、途中で返すことはできない
- クロージャのスコープは親とは独立したスコープである
- 可変な独占者は値の独占者だけで、宣言後は孤立し続け、副作用によって値を書き換えることができる
- スコープの値はそのスコープ内の外出者による値でなければならず、スコープの値は単独値となる
- 孤立した独占者を外出者としてスコープの値とすることができ、スコープの値は単独値となる
デフォルトハンドラ
Cargryでの導入を考えている機能。ライブラリが用意したハンドラを使うことを明示することで、コンパイラが適切なハンドラを挿入する仕組み。defaultキーワードの有無で、デフォルトハンドラを許可するかしないかを選択できるようにする予定である
終わりに
今までと違って、最適化に関するルールが撤廃されたり、スコープを跨ぐ値に関する定義が変更されたりしました
今後新たな問題が見つかるにつれて、用語やルールが変わって行きます
最後まで読んでくださりありがとうございました