スクリプト言語を作りたい
#ideae
名前: RocSho
緑青
Rustっぽさ
WebAssembly で動くスクリプト言語
シェルスクリプトはあまりまともでない
Pythonなどはバージョン問題がある
WASMにコンパイルしてWASIを使える軽妙な言語がほしい
実行時エラーを減らしたい
静的型付け言語
バチバチな型推論
Hindley-Milner
Crystal とか強いらしいけど
関数型
ML系の関数定義
自動カリー化
再帰は明示的に
Rustスタイルのシャドーイングがしたいので
パイプ演算子
関数barについてfoo.barできるやつあってもよい
関数合成
既定でイミュータブル
トレイト
Rustのと同じ感じ
ある型が実装していてほしいメソッドを定義する
HaskellのNumとかFloatingみたいな抽象化もほしい
参照とコピーを区別したい
既存の言語が雑にやってきた部分
ここは Rust っぽい?
所有権チェッカーを作りたくない
ムーブの概念を消して変数への束縛は基本全てコピーにするみたいな?
Rustでいうと全部の型がClone
メモリ解放はどうやるんだ
文法はF#っぽい感じか?
Rustは重いのでML系の感じで
括弧でもいい
オブジェクト指向
JavaScriptのようにさくりと書けるレコード機能がほしい
シングルトンでは
プロパティアクセスを関数にしたい
レコードの型推論
構造的部分型
JavaScript的に手軽に書けてjqみたいなフィルタで扱えてしかも型がつく
let f r = r.foo に {foo: a} -> a みたいな型がついてほしい
文字列はUTF-8
依存関係をまともに扱いたい
WASMパッケージマネージャーがどうなるか?
型
ユーザ定義型名は大文字から始める。組み込み型名もそうしたい。
Bool は真偽値。True と False だけ。条件分岐とかで使う。
整数は 37 のようなリテラルで Int 型。スクリプト用途なんだからビット数なんてどうでもいいだろう。
浮動小数点数型も整数と同様に Float を使う感じで、IEEE754。
数値型に共通の型クラスとして Num を用意して、+ のような演算子は Num インスタンスに適用する関数にしたい。OCaml のような +. とかは見たくない。
文字型は4バイトのUnicode Scalar Valueがいいんじゃない?知らんけど。本当に必要なのかから検討したほうがいい。
文字列型 String は鋼の意志を持ってUTF-8にする。Rustでは実体は Vec<u8> になっているし、そのように持ったほうがいいのか。そもそもWASM側の仕様でそうなる感じがする。文字列リテラルは "" が無難だが、\`A "black" dog\` のようにバッククオートを使う文法にしてもいいかもしれない。どちらにせよ ##"#"fiii"#"## のようなエスケープをできるようにする。
TypeScriptみたいなリテラル型がほしい。そうするとユニオンが必要になり、関数のunionとかが出てきて頭が崩壊する。関数のunionが出てくると必然的にintersectionが出てきて終わりになる。
変数定義
変数宣言は let を使って行う。
code:変数宣言
let h = 42
h + 58
F#と同じ。
let式は一行で書ける。
code:一行
let h = 42 in h + 58
可変変数let mutを作るか迷う。RustとF#にはあってOCamlにはない。
型注釈は後置する。
code:型注釈
let h: String = "foo";
Rustと同じ。
ただし
code:型注釈
val h: String
let h = "foo"
のような文法も許容するかもしれない。
レコード
JavaScriptでいうオブジェクト。レコードへのアクセスを関数にしたいという欲がある。
code:record
// JS-style
let record = { age: 12 }; // record: { age: Int }
println record.age; // ドット
// SATySFi-like
let record = (| age: 12 |); // SATySFiっぽいタイプも検討
println record#age // .を#に置き換えただけ
println (#age record) // #foo が関数になるタイプ
match
$ \texttt{match} \space expr \space \texttt{with} \space expr
関数
関数呼び出しはかっこ不要。
code:fn
print "hi"
関数定義もletを使って行う。
code:関数
let f x = x + 1
F#と同じ。Rustは冗長で部分適用の扱いが面倒。
再帰的定義には rec をつける。
code:関数
let rec fact n =
if n == 0
1
else
n * fact(n - 1);
F#と同じ。このようにしないと let a = a + 3 のようなシャドーイングを意図したコードが(無限)再帰になってしまう。
名前付き引数はなし。レコードを使う。
code:引数にレコード
val f: (| a: Int, b: String |) -> Unit
f (|
a: 32,
b: "hogehoge",
|)
直和型
1個以上のバリアントから1つ選ぶ型。ADT。
code:adt
data Bool = True | False
data Option a = Some a | None
レコード
code:record
type Square = {
size : Int
}
トレイト
型クラス相当。
code:typeclass
trait Area
val area : Self -> Float
impl Square for Area
let area { size } =
size * size
let area_sum a b =
area a + area b
Algebraic Effects
code:ae
effect log : Int -> Unit
with handler
| log a -> println(a)
log 1