$30 off During Our Annual Pro Sale. View Details »

AltJS を作るなら型変換を入れた方がいい

cannorin
September 24, 2022

AltJS を作るなら型変換を入れた方がいい

情報科学若手の会で発表したスライドです.

cannorin

September 24, 2022
Tweet

More Decks by cannorin

Other Decks in Programming

Transcript

  1. AltJS を作るなら 多分型変換を入れた方がいい cannorin

  2. 2 関数型プログラム言語や型システムについての マニアックな知識が必要な部分があります そのようなスライドにはもくもくマークを付けました→ 分からない場合は聞き流して大丈夫なように頑張ります 

  3. 3 最強の AltJS を作りたい ですよね?

  4. 4 最強の AltJS とは… ・軽量構文! ・静的型付き!! ・関数型プログラミング!!! ・ JS の資産がそのまま使える!!!!

    これらだけ なら簡単! どうやれば????
  5. 5 JS の資産を活用 ・ Definitely Typed というものがある https://github.com/DefinitelyTyped/DefinitelyTyped npm パッケージの

    TypeScript 用型定義 (.d.ts) がいっぱいある → .d.ts から AltJS 用のバインディングを   自動生成したい!!
  6. 6 ここで自己紹介 .d.ts から OCaml 系 AltJS (js_of_ocaml, ReScript) 用の

    バインディングを生成するツールを作っています 他には AltJS コンパイラの中身をいじったり OCaml や F# のツール・ライブラリに contribute したり
  7. 7 TypeScript の特徴 ・クラスベース OOP ➾ 関数型プログラミングとは相性悪め!(今回はこれの話) ・構造的部分型付け ➾ 多くの

    TS プログラマは名前的部分型付けのつもりで   書いているので,あまり気にしなくて OK かも ・充実した型操作 ➾ Turing 完全になっちゃうので,ある程度以上は諦める
  8. 8 関数型 AltJS に変換? ・クラスベース OOP → 関数型プログラミングとは相性悪め!(今回はこれの話) ・構造的部分型付け →

    多くの TS プログラマは名前的部分型付けのつもりで   書いているので,あまり気にしなくて OK かも ・充実した型操作 → Turing 完全になっちゃうので,ある程度以上は諦める
  9. 9 クラスベース OOP の変換 ・ OOP をそのまま入れられるなら OK 例 :

    F# ベースの AltJS: Fable (C# との連携用に元々入ってる ) ・そうでない場合,以下の要素が問題になる ①メソッドのオーバーロード (関数のオーバーロードは関数型と相性悪い) ②クラス・インターフェースの継承 (何らかの方法で部分型付けをやる必要あり)
  10. 10 ① オーバーロード 以下のような .d.ts を考えよう

  11. 11 ① オーバーロード Hindley-Milner 型推論にオーバーロードを加えると決定不能になる [1] → 決定可能になるようにする or 諦める

    決定可能になるようにする… → 型クラスを導入する(例 : PureScript ) → 制限された形のオーバーロードのみ受け付けるようにする [2] (難しいので,やってる AltJS は多分ない) 諦める… → 決定不能でもいいか~(例: Fable) → オーバーロードごとに関数をリネームする(例: js_of_ocaml, ReScript) 型 推 論 で き な い か も し れ な い
  12. 12 ① オーバーロード(型クラス) PureScript を例に… • オーバーロードされた foo 用の型クラス Fooable

    を作る • Number 版と String 版を別々に import して, それぞれ Fooable のインスタンスにする • すると一個の foo に String を渡しても Number を渡しても使えるようになる → そもそも言語に型クラスを実装するのが超大変 → 自動生成はそんなに大変ではない ( 1 個のメソッドに対して 1 個の型クラスを作る必要があるが…) → ユーザとしては使いやすい (が,型クラス自体が難しい…)
  13. 13 ① オーバーロード(リネーム) ReScript を例に… • Number と String に対してそれぞれ

    fooNumber, fooString を external で定義 (ただし,両者とも同じ foo にコンパイルさせる) • 使う際は,引数の型に応じて fooNumber か fooString を使い分ける → 言語側の実装はとても楽 ( FFI 対象の名前を指定できるようにするだけ) → 自動生成もリネームするだけなので楽 (リネーム時に名前衝突しないよう気を配る必要あり) → ユーザとしては少し使いづらい
  14. 14 ① オーバーロード 型クラスは言語機能としてかなり“重たい” ・例えば,存在型と組み合わせると型推論が決定不能になる [3] これに関しては諦めたほうが楽だと思う… ・型クラスで決定不能になるくらいなら最初から決定不能にしても同じ ・リネームはエディタの補完で何とかなる範囲なので,  リネームで頑張りたい

  15. 15 ② 継承 以下のような .d.ts を考えよう

  16. 16 ② 継承 素朴にやると大変ヤバい • 継承したものも含めてメソッド全部追加しちゃお O(n2) で コード増加 (

    n: 型の数)
  17. 17 ② 継承 素朴にやると大変ヤバい • 継承元の型に変換する関数を足そう d->D.to_B ->B.to_A ->A.foo(42.0)

  18. 18 ② 継承 素朴にやると大変ヤバい • 継承元の型には全部一発で変換できるようにするか… O(n2) で コード増加 (

    n: 型の数)
  19. 19 ② 継承 Hindley-Milner 型推論に部分型付けを加えると実用上しんどい [4] → もっと軽量な仕組みで継承を再現したい われわれが求める要件としては, 1.

    コード増加が O(n2) とかにならないようにしたい 2. 継承元の型には全て一発で変換できるようにしたい(例: D から A ) 3. 外部 (TypeScript) の世界から来た型にのみ上記ができれば十分 → このような型システムの研究はあまりされていないように見える (近いことをやっている論文 :[5] )
  20. 20 ② 継承 : でもファンクタ使えばいいじゃん? → 継承時の型変数の数の変化が問題になる • C では型変数

    ’ a が増えてしまっている → A.Impl をそのまま include できない • これを解消するには,’ a もファンクタ の引数として取るしかない → C を異なる ‘ a で使うたびに ファンクタを適用しないといけなくなる • さすがにそれでは使いづらいのではないか ( AltJS としては OCaml ユーザだけでなく, 既存の JS ユーザも取り込みたいところ)
  21. 21 ② 継承 : でも row polymorphism 使えばいいじゃん? → オーバーロードされたメソッドが問題になる

    • c は a も b も継承していることにしたい • row polymorphism で部分型になるには, 名前と型が一致してないといけない • しかし,同じ名前で複数のフィールドを レコード c に定義することはできない • c でどちらかをリネームすると. row polymorphism が壊れてしまう • a か b の foo を事前にリネームしておくことも できない(もし別ライブラリで定義されてたら…)
  22. 22 ② 継承 : row polymorphism + phantom types ・

    row polymorphism をそのまま使うのではなく,  「継承している型の列」に対して使う ・「型の列」は phantom type として保持 ・例 : B は A を継承しているので #B と #A を持つ ・この手法ならわれわれの求める要件を満たせる   - コード増加は O(n) に収まる   - 明示的に書く必要はあるが, D→A の変換は一発 → これをきちんと言語機能として組み込めば,   型推論を決定可能に保ちつつ, TypeScript の継承   をうまく翻訳できるのではないだろうか?
  23. 23 ② 継承 なんにせよ, JavaScript/TypeScript の世界からやってきた型を, 継承関係に従って簡単に変換できるような専用の仕組み が,最強の AltJS を作るためには必要

    そして,それは最強の AltJS の 「最強性」を失うことなしに実現できそうな気がする
  24. 24 参考文献 [1] Dennis M. Volpano and Geoffrey S. Smith.

    On the complexity of ML typability with overloading. https://ecommons.cornell.edu/handle/1813/7050 [2] Geoffrey S. Smith. Polymorphic Type Inference for Languages with Overloading and Subtyping. https://ecommons.cornell.edu/handle/1813/7070 [3] Sulzmann, Martin & Schrijvers, Tom & Stuckey, Peter. Principal Type Inference for GHC-Style Multi-parameter Type Classes. https://www.researchgate.net/publication/221323263 [1] Dennis M. Volpano and Geoffrey S. Smith. On the complexity of ML typability with overloading. https://ecommons.cornell.edu/handle/1813/7050 [4] François Pottier. Type Inference in the Presence of Subtyping: from Theory to Practice. https://hal.inria.fr/inria-00073205 [5] Fluet, Matthew and Pucella, Riccardo. Phantom Types and Subtyping. https://arxiv.org/abs/cs/0403034