Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

cannorin
September 24, 2022

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

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

cannorin

September 24, 2022
Tweet

More Decks by cannorin

Other Decks in Programming

Transcript

  1. 5 JS の資産を活用 ・ Definitely Typed というものがある https://github.com/DefinitelyTyped/DefinitelyTyped npm パッケージの

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

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

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

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

    F# ベースの AltJS: Fable (C# との連携用に元々入ってる ) ・そうでない場合,以下の要素が問題になる ①メソッドのオーバーロード (関数のオーバーロードは関数型と相性悪い) ②クラス・インターフェースの継承 (何らかの方法で部分型付けをやる必要あり)
  6. 11 ① オーバーロード Hindley-Milner 型推論にオーバーロードを加えると決定不能になる [1] → 決定可能になるようにする or 諦める

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

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

    fooNumber, fooString を external で定義 (ただし,両者とも同じ foo にコンパイルさせる) • 使う際は,引数の型に応じて fooNumber か fooString を使い分ける → 言語側の実装はとても楽 ( FFI 対象の名前を指定できるようにするだけ) → 自動生成もリネームするだけなので楽 (リネーム時に名前衝突しないよう気を配る必要あり) → ユーザとしては少し使いづらい
  9. 19 ② 継承 Hindley-Milner 型推論に部分型付けを加えると実用上しんどい [4] → もっと軽量な仕組みで継承を再現したい われわれが求める要件としては, 1.

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

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

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

    row polymorphism をそのまま使うのではなく,  「継承している型の列」に対して使う ・「型の列」は phantom type として保持 ・例 : B は A を継承しているので #B と #A を持つ ・この手法ならわれわれの求める要件を満たせる   - コード増加は O(n) に収まる   - 明示的に書く必要はあるが, D→A の変換は一発 → これをきちんと言語機能として組み込めば,   型推論を決定可能に保ちつつ, TypeScript の継承   をうまく翻訳できるのではないだろうか?
  13. 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