理想の言語
2019/11時点
文章
特筆して面白いところはない、普通だけど現実的で各言語のいいところが合わさったような言語
読みやすいコードになる
読みやすいコードしか書けない
本質的なロジックに着目できる
書くよりも読む方優先
複雑なことができない
型レベルプログラミングとかできない
コンパイルが早い
言語機能
プロファイル取りやすい
テストが書きやすい
DI みたいなことがしやすい
その他
代数的データ型
Hoge of int * int じゃなくて Hoge Int Int がいい
並行処理
アクターモデルがいいな
monitor がほしい
分散処理
うーん
互換性保つの難しいしなくても?
正格評価
型クラス
モジュール、モジュールファンクタ
HKT?
モナド?
ML + Erlang + Haskell + Go
全部非同期 IO
Go はそうなっているらしい
全部に async / await ついている感じというのを聞いた
IO モナドなし
面倒なので
型クラス/トレイト
ほしい
ref あり
Actor に閉じ込めるのでもいいのだろうか
HKT
モナドはほしい
エラー
Result 型 (API は基本全部 Result 型で返ってきてほしい)、throw (大域脱出)、exit (アクターの終了) の3つ
throw はいらないかも。どうだろう。使ってみてほしくなったらという感じ
Erlang の error は error と exit の使い分けが面倒なのでいらない
エラーの型は?
大統一エラー型? (Go の error みたいな)
それとも型クラスだけ用意する? (Haskell の Exception、だっけ)
エラーの伝搬のさせかたは?
モジュール
名前空間をファイル内に複数作れる
これは微妙なところかも。ある程度コーディングスタイルを強制するほうがよさそう
ほしくなった。モジュールタイプをインタフェースとして、モジュールファンクタで依存を入れ込みたい。
でも型クラスとバッティングしてしまったりするのだろうか。
Haskell は型クラスを各関数に書かないといけない、型シグネチャが大きくなりやすい、モジュールファンクタならモジュール内の関数はいつでもそれを使えるので型シグネチャに書く必要はない
pros: 型シグネチャが短くなりやすい
cons: 各関数のシグネチャを見ただけではなにに依存しているかがわからない
export は列挙ではなく関数単位で見たらわかるように
モジュールは基本書くのを推奨するようなシンタックス
でもリスト処理で List.map f |> List.filter g |> みたいになって冗長だろうか…
メソッドは?
ローカルオープンは?
エイリアスは?
正格評価
並行処理が書きやすい (Actor)
リンク、モニター (モニターだけでもいいかも) がほしい
ライブラリレベルで実現できるならそれでOK
分散
なくてもいいかも?どうだろう
RIO は ReaderT env IO
IO はないのでいらない
エラーは例外
mli みたいなファイルはいらない。トップレベルの関数には型を書く
なんか Result になるべきなのにわざとそうしていないやつは unsafe とかつける?
head -> unsafe_head とか
Result a b -> a の関数とか expect? unsafe_get?
プロセスが終了する可能性のある関数?
めんどいかな…
自分の頭の悪さを言語のせいにできる
シンタックス
オフサイドルールではない
{} を使いたい
演算子に記号は使えない
どこまでやるか
: を 〜 の型は という意味で使いたい
直和・直積書きたい。タグなしでレコード使いたい。レコードフィールドは関数じゃない。
メソッドは?
list.map f or map f list
list |> map f |> filter g
(list.map f).filter g
list.map(f).filter(g) なるほど
デフォルトカリー化関数とメソッドは相性があんまりよくなさそう
list |> _.map f |> _.filter g
filter g . map f $ list
うーん
ES Next のパイプライン演算子みたいな例もある
上から下に読めるようにする
ネストが深くなりにくい
モナド専用シンタックス
code:pseudo
// 公開されているかどうかの判断はどうする
// Go の、大文字だったら公開のやつは結構好き
// - private なのか public なのかがひと目で簡単にわかるため
// - モジュールついてたら public でもいいかも
module IO {
readline : Result String Error =
...
// 引数どうする
writeline : (str : String) -> Result () Error = {
let newlined = str ++ "\n";
print stdio newlined
}
}
str <- IO.readline
IO.writeline str