依存して型付けされないのはなぜですか?


161

「Haskellは徐々に依存型付き言語になりつつある」という意見を反映するいくつかの情報源を見てきました。含意は、ますます多くの言語拡張により、Haskellがその一般的な方向に向かっていることですが、まだそこにはありません。

基本的に私が知りたいことが2つあります。1つ目は、非常に簡単に言うと、「依存型付き言語であること」は実際に何を意味するのでしょうか。(うまくいけば、あまり技術的ではありません。)

2番目の質問は...欠点は何ですか?つまり、人々は私たちがそのように向かっていることを知っているので、それにはいくつかの利点があるに違いありません。それでも、私たちはまだそこにいないので、人々がずっと先に行くのを止めるいくつかの欠点があるに違いありません。問題は複雑さが急激に増加しているという印象を受けます。しかし、依存するタイピングが何であるかを本当に理解していないので、私には確かにわかりません。

知っているのは、依存型プログラミング言語について読み始めるたびに、テキストがまったく理解できないことです...おそらくそれが問題です。(?)


10
簡単に言えば、用語(計算)に依存する型を記述できます。これは、プログラムのあらゆる側面について型を指定するのに十分であるため、型システムが完全なプログラム仕様に対応できることを意味します。問題は、型が計算に依存しているため、型チェックを実行するのが非常に難しいことです(一般的には不可能です)。
GManNickG 2012年

27
@GManNickG:型チェックは完全に可能です。型推論は別の問題ですが、GHCのさまざまな拡張機能は、すべての型を推論することが可能であるという考えを放棄して以来、長い間使用されていませんでした。
CAマッキャン

7
私が正しく理解している場合の欠点は、依存型タイピングを正しく(たとえば、使いやすく根拠のある方法で)行うのが難しいことです。
2012年

1
@CAMcCann:はい、間違いです。
GManNickG 2012年

4
私は誰もが1つの大きな実用的な欠点を指摘したとは思わない:すべてのコードが正しいという証明を書くのはかなりめちゃくちゃ面倒です。型推論を自動的に行うことはできないため(「hellaの強力な」ロジックで証明される定理に対応)、プログラムの注釈を証明の形式で記述する必要があります。これは明らかに煩わしくなり、しばらくすると、特にHaskellで一般的に行われるより複雑なモナディックマジックでは、実行が困難になります。私たちが最近来ているのに最も近いのは、これのほとんどを私たちのために行うか、または私たちに優れたプリミティブのセットを提供する言語です。
Kristopher Micinski、2012年

回答:


21

依存型付けは、実際には値と型レベルの統合に過ぎないため、型の値をパラメーター化できます(既に型クラスとHaskellのパラメトリック多態性で可能)値の型をパラメーター化できます(厳密に言えば、Haskellではまだ可能です) 、DataKinds非常に近くなりますが)。

編集: どうやら、この時点から、私は間違っていました(@pigworkerのコメントを参照)。残りは、私が与えられた神話の記録として保存します。:P


私が聞いたことによると、完全依存型への移行に関する問題は、型と値のレベル間のフェーズ制限を破り、Haskellが消去された型を含む効率的なマシンコードにコンパイルされることです。現在の技術レベルでは、依存型言語、ある時点で(すぐに、または依存型バイトコードなどにコンパイルされた後で)インタープリターを通過する必要があります。

これは必ずしも基本的な制限ではありませんが、この点で有望と思われる現在の研究について個人的には知りませんが、GHCにはまだ含まれていません。他の誰かがもっと知っていれば、私は修正されてうれしいです。


46
あなたの言うことはほぼ完全に偽です。私はあなたを完全に非難しているわけではありません。それは標準の神話を事実として繰り返します。Edwin Bradyの言語であるIdrisは、型の消去を実行し(実行時の動作は型に依存しないため)、かなり標準的なラムダリフトスーパーコンビネーターエンコーディングを生成し、そこからストックGマシン技術を使用してコードを生成します。
pigworker

3
余談ですが、最近誰かがこの論文を指摘しました。私が言うことができることから、Haskellは依存的に親切になります(つまり、タイプレベルの言語は依存的に型指定されます)。
Ptharienの炎2012

8
はい、その論文は、型を型レベルのものに依存させる方法を示すために(そして型/種類の区別を排除するために)ほとんどの方法で行っています。すでに議論されているもっともらしいフォローアップは、実際の依存関数の型を許可することですが、それらの引数を、値と型の両方のレイヤーに存在できる言語のフラグメントに制限します(データ型の昇格のおかげで重要ではなくなりました)。これは、現在「偽造」を望ましいものにするよりも複雑にするシングルトン構造の必要性を排除します。私たちは着実に本物に近づいています。
pigworker、

13
依存型をHaskellに改良する実用的な質問がたくさんあります。従属関数空間のこの制限された形式を取得した後も、型レベルで許可される値言語のフラグメントをどのように拡大するか、そしてその方程式理論はどうあるべきか(2 + 2に4など)。最初から依存して型付けされた言語が最初から離れて設計するという厄介な問題がたくさんあります(たとえば、下)。
pigworker

2
@pigworker合計であるHaskellのクリーンなサブセットはありますか?もしそうなら、それを「値層と型層の両方に存在できる言語の断片」に使用できませんか?そうでない場合、それを作成するには何が必要ですか?
Ptharienの炎2012

223

依存型付けされたHaskell、今?

Haskellは、ある程度、依存型付け言語です。型レベルのデータの概念があり、今DataKindsではのおかげでより賢く型付けされていGADTsます。また、型レベルのデータにランタイム表現を与えるためのいくつかの手段()があります。したがって、ランタイムのものの値は効果的に型表示されます。これは、言語が依存して型付けされることを意味します。

単純なデータ型は、種類レベルに昇格されるため、それらに含まれる値を型で使用できます。したがって、典型的な例

data Nat = Z | S Nat

data Vec :: Nat -> * -> * where
  VNil   :: Vec Z x
  VCons  :: x -> Vec n x -> Vec (S n) x

可能になり、それにより、次のような定義

vApply :: Vec n (s -> t) -> Vec n s -> Vec n t
vApply VNil         VNil         = VNil
vApply (VCons f fs) (VCons s ss) = VCons (f s) (vApply fs ss)

いいですね。その長さnはその関数の純粋に静的なものであり、入力と出力のベクトルが同じ長さであることを保証することに 注意してくださいvApply。これとは対照的に、それは作る機能を実装するために(すなわち、不可能)非常にトリッキーだn与えられたのコピーをx(されるであろうpurevApplyさん<*>

vReplicate :: x -> Vec n x

実行時に作成するコピーの数を把握することが重要であるためです。シングルトンを入力します。

data Natty :: Nat -> * where
  Zy :: Natty Z
  Sy :: Natty n -> Natty (S n)

昇格可能なタイプの場合は、その値の実行時の複製が存在する、昇格されたタイプにインデックスが付けられたシングルトンファミリを構築できます。Natty ntype-levelのランタイムコピーのタイプですn :: Nat。私たちは今書くことができます

vReplicate :: Natty n -> x -> Vec n x
vReplicate Zy     x = VNil
vReplicate (Sy n) x = VCons x (vReplicate n x)

したがって、ランタイムレベルの値に型レベルの値が連結されています。ランタイムコピーを検査すると、タイプレベルの値の静的な知識が絞り込まれます。用語とタイプは分離されていますが、シングルトン構造を一種のエポキシ樹脂として使用することにより、依存型の方法で作業でき、フェーズ間に結合を作成します。これは、型で任意の実行時式を許可するまでには長い道のりですが、それは何もではありません。

厄介なのは何ですか?何が欠けていますか?

このテクノロジーに少し圧力をかけて、何がぐらつくのかを見てみましょう。シングルトンはもう少し暗黙的に管理可能である必要があるという考えを得るかもしれません

class Nattily (n :: Nat) where
  natty :: Natty n
instance Nattily Z where
  natty = Zy
instance Nattily n => Nattily (S n) where
  natty = Sy natty

たとえば、

instance Nattily n => Applicative (Vec n) where
  pure = vReplicate natty
  (<*>) = vApply

これは機能しますが、これは、元のNatタイプが3つのコピー(種類、シングルトンファミリー、シングルトンクラス)を生成したことを意味します。明示的なNatty n値とNattily n辞書を交換するためのかなり不格好なプロセスがあります。さらに、そうでNattyはありませんNat。実行時の値に何らかの依存関係がありますが、最初に考えた型には依存していません。完全に依存型付けされた言語が依存型をこれほど複雑にすることはありません!

一方、Nat昇進はVecできますが、できません。インデックス付きの型でインデックスを付けることはできません。依存型言語に完全に依存することはそのような制限を課しません。そして、依存型ショーオフとしての私のキャリアの中で、私は話に2層インデックスの例を含めることを学びました。カードの家のように折りたたまれるのを期待するのは難しいですが可能です。どうしたの?平等。GADTは、コンストラクターに特定の戻り値の型を明示的な等式要求に与えるときに暗黙的に達成する制約を変換することによって機能します。このような。

data Vec (n :: Nat) (x :: *)
  = n ~ Z => VNil
  | forall m. n ~ S m => VCons x (Vec m x)

2つの方程式のそれぞれで、両側に種類がありNatます。

次に、ベクトルにインデックスを付けたものに対して同じ翻訳を試みます。

data InVec :: x -> Vec n x -> * where
  Here :: InVec z (VCons z zs)
  After :: InVec z ys -> InVec z (VCons y ys)

なる

data InVec (a :: x) (as :: Vec n x)
  = forall m z (zs :: Vec x m). (n ~ S m, as ~ VCons z zs) => Here
  | forall m y z (ys :: Vec x m). (n ~ S m, as ~ VCons y ys) => After (InVec z ys)

そして今、私たちは、2つの側が構文的に異なる(ただし、等しい可能性がある)種類の間でas :: Vec n xVCons z zs :: Vec (S m) xどこに方程式の制約を形成します。現在、GHCコアはそのようなコンセプトには対応していません。

他に何が欠けていますか?まあ、Haskellのほとんどは型レベルにありません。宣伝できる用語の言語には、実際には変数と非GADTコンストラクターしかありません。それらを取得したら、type family機械でタイプレベルのプログラムを記述できます。それらのいくつかは、用語レベルで記述することを検討する関数に非常に似ている場合があります(たとえば、Nat追加機能を備えているため、追加するのに適したタイプを指定できますVec)。 、しかしそれは単なる偶然です!

もう1つ欠けているのは、実際には、値によって型にインデックスを付ける新しい機能を利用するライブラリです。この勇敢な新しい世界で何が起こりFunctor 、どうMonadなるのでしょうか?考えていますが、まだやることがたくさんあります。

タイプレベルのプログラムの実行

Haskellは、ほとんどの依存型付きプログラミング言語と同様に、2つの 操作上のセマンティクスを持っています。ランタイムシステムがプログラムを実行する方法(閉じた式のみ、型の消去後、高度に最適化)と、型チェッカーがプログラムを実行する方法(型ファミリー、「型クラスProlog」、開いた式)があります。Haskellでは、実行されるプログラムが異なる言語であるため、通常は2つを混同しないでください。依存型付けされた言語には、同じプログラム言語の実行時モデルと静的実行モデルが別々にありますが、心配する必要はありません。実行時モデルでは、型消去と実際の証明消去を実行できます。それがCoqの抽出です。メカニズムはあなたに与える; これは少なくとも、Edwin Bradyのコンパイラーが行うことです(ただし、Edwinは不必要に重複した値、および型と証明を消去します)。フェーズの区別は 、もはや構文カテゴリの区別ではないかもしれませんが、それは健在です。

依存して型付けされた言語は、全体として、タイプチェッカーが長い待機よりも悪いことを恐れずにプログラムを実行できるようにします。Haskellがより依存的に型付けされるようになると、静的実行モデルがどうあるべきかという疑問に直面します。1つのアプローチとして、静的実行を関数全体に制限することもできます。これにより、同じ自由に実行できますが、データとコデータを(少なくとも型レベルのコードでは)区別しなければならないため、終了または生産性を強化する。しかし、それが唯一のアプローチではありません。プログラムを実行することに消極的なはるかに弱い実行モデルを自由に選択できますが、計算だけで得られる方程式が少なくなります。そして実際には、それがGHCが実際に行っていることです。GHCコアのタイピングルールは実行について言及していません プログラム、ただし方程式の証拠をチェックするためだけ。コアに変換すると、GHCの制約ソルバーはタイプレベルのプログラムを実行しようとし、指定された式がその正規形に等しいという証拠の小さな銀色の痕跡を生成します。この証拠生成方法は、少し予測不可能であり、必然的に不完全です。たとえば、恐ろしい再帰の恥ずかしがり屋と戦いますが、それはおそらく賢明です。心配する必要のないことの1つIO は、タイプチェッカーでの計算の実行launchMissilesです。タイプチェッカーは、ランタイムシステムが行うのと同じ意味を与える必要がないことに注意し てください。

ヒンドリー・ミルナー文化

Hindley-Milner型システムは、4つの異なる区別の本当に驚くべき一致を実現しますが、不幸な文化的副作用により、多くの人々は区別を区別できず、一致が避けられないと想定できません。私は何を話しているのですか?

  • 用語タイプ
  • 明示的に書かれたもの暗黙的に書かれたもの
  • 実行時に存在実行時前に消去
  • 非依存抽象化依存定量化

私たちは用語を書き、タイプを推測されたままにして、それから消去することに慣れています。私たちは、対応する型の抽象化と型変数の定量化に慣れており、アプリケーションはサイレントで静的に発生します。

これらの区別が外れる前に、バニラHindley-Milnerからあまり遠くに向きを変える必要はありません。それは悪いことではありません。まず、いくつかの場所でそれらを記述したい場合は、より興味深いタイプを使用できます。一方、オーバーロードされた関数を使用する場合、型クラスの辞書を記述する必要はありませんが、これらの辞書は実行時に確実に存在(またはインライン化)されます。依存型付き言語では、実行時に型だけでなく、(型クラスと同様に)暗黙的に推論された値の一部が消去されないことを期待しています。たとえば、vReplicateの数値引数は、目的のベクトルのタイプから推測できることがよくありますが、実行時にそれを知る必要があります。

これらの偶然はもはや成立しないため、どの言語設計の選択を検討する必要がありますか?たとえば、Haskellがforall x. t数量詞を明示的にインスタンス化する方法を提供しないことは正しいですか?xタイプチェッカーがunifiying tで推測できない場合、他に何xがあるべきかを言う方法はありません。

より広義には、「型推論」を、すべてを持っているか、まったく持っていないモノリシックな概念として扱うことはできません。まず、「一般化」の側面(ミルナーの「レット」ルール)を分離する必要があります。これは、存在するタイプの制限に大きく依存して、「特殊化」の側面(ミルナーの「var」 "ルール)これは、制約ソルバーと同じくらい効果的です。トップレベルの型は推測するのが難しくなると予想できますが、その内部の型情報はかなり簡単に伝播されます。

Haskellの次のステップ

種類と種類のレベルが非常によく似ています(そして、それらはすでにGHCの内部表現を共有しています)。それらをマージすることもできます。* :: *できれば取るのは楽しいでしょう。ボトムを許可したときに論理的健全性をずっと以前に失って いましたが、タイプ 健全性は通常、より弱い要件です。確認する必要があります。明確なタイプ、種類などのレベルが必要な場合は、少なくともタイプレベル以上のすべてを常に昇格できるようにすることができます。種類レベルでポリモーフィズムを再発明するのではなく、タイプですでに使用しているポリモーフィズムを再利用することは素晴らしいことです。

との種類が構文的に同一でない異種の方程式を許可することにより、現在の制約システムを単純化および一般化する必要a ~ baあり bます(ただし、同等であることが証明できます)。それは依存関係をはるかに扱いやすくする古い技法(私の論文では前世紀)です。GADTで式の制約を表現できるため、昇格できるものの制限を緩和できます。

依存関数タイプを導入することにより、シングルトン構築の必要性を排除する必要がありpi x :: s -> tます。そのようなAタイプを持つ関数が適用され得る明示的タイプのいずれかの式にsに住んでいる交差点(詳細は後に来るようにと、そう、変数、コンストラクタ)タイプと用語の言語。対応するラムダとアプリケーションは実行時に消去されないため、次のように記述できます。

vReplicate :: pi n :: Nat -> x -> Vec n x
vReplicate Z     x = VNil
vReplicate (S n) x = VCons x (vReplicate n x)

交換なしNatNatty。のドメインはpi任意の昇格可能なタイプにすることができるため、GADTを昇格できる場合は、従属数量詞シーケンス(またはde Briuijnがそれらを呼び出した「望遠鏡」)を書き込むことができます。

pi n :: Nat -> pi xs :: Vec n x -> ...

必要な長さに。

これらのステップの要点は、弱いツールや不格好なエンコーディングを使用する代わりに、より一般的なツールを直接操作することで複雑さを排除することです。現在の部分的な賛同により、Haskellのある種の依存型の利点は、必要以上に高くなります。

あまりにもハード?

依存型は多くの人を緊張させます。彼らは私を緊張させますが、私は緊張するのが好きです、または少なくとも私はとにかく緊張しないのは難しいと思います。しかし、それはトピックの周りにかなりの無知の霧があることを助けません。その一部は、私たち全員がまだ学ぶべきことがたくさんあるという事実によるものです。しかし、それほど過激でないアプローチの支持者は、常に事実が完全に彼らにあることを確認せずに、依存型の恐れを引き起こすことが知られています。名前は付けません。これらの「決定不可能な型チェック」、「不完全なチューリング」、「フェーズの区別なし」、「型の消去なし」、「どこでも証明」などの神話は、たとえごみでも残っています。

依存して型付けされたプログラムが常に正しいことが証明されなければならないというのは、確かにそうではありません。プログラムの基本的な衛生状態を改善し、完全な仕様に至るまで行くことなく、型に追加の不変条件を適用することができます。この方向の小さなステップは、追加の証明義務がほとんどまたはまったくない、非常に強力な保証をもたらすことがよくあります。依存して型付けされたプログラムが必然に証明でいっぱいになることは真実ではありません。実際、私は通常、コードに証明の存在を見つけて、自分の定義疑問投げかけます

なぜなら、アーティキュラシーの増加と同様に、フェアなだけでなくファウルな新しいことを自由に言うことができるからです。たとえば、二分探索木を定義するための不必要な方法はたくさんありますが、それは良い方法がないという意味ではありません。たとえそれがエゴにそれを認めさせるようにへこませたとしても、悪い経験は改善することができないと思い込まないことが重要です。従属定義の設計は学習を必要とする新しいスキルであり、Haskellプログラマーであっても自動的にエキスパートになるわけではありません!そして、いくつかのプログラムが不正であったとしても、なぜ他の人が公正である自由を否定するのでしょうか?

なぜまだHaskellに悩むのですか?

依存型が本当に好きですが、私のハッキングプロジェクトのほとんどはまだHaskellにあります。どうして?Haskellには型クラスがあります。Haskellには便利なライブラリがあります。Haskellには、効果を備えたプログラミングの(理想的とは言えませんが)実行可能な処理があります。Haskellには、強力なコンパイラーがあります。依存型付けされた言語は、コミュニティとインフラストラクチャの成長のかなり早い段階にありますが、メタプログラミングやデータ型のジェネリックスなどによって、可能なことの世代交代が現実のものとなります。しかし、依存型へのHaskellのステップの結果として人々が何をしているのかを見回して、現在の世代の言語を前進させることによって得られる多くの利点があることも確認する必要があります。


6
まだDataKindsのことは気にしていません。主に私がこのようなことをしたいので:fmap read getLine >>= \n -> vReplicate n 0。お気づきのように、これはそれNattyから離れた方法です。さらに、vReplicateは、実際のメモリアレイ、のようなものに翻訳可能であるべきでnewtype SVector n x = SVector (Data.Vector.Vector x)n種類有するNat(または類似の)。おそらく、「依存型のショーオフ」のもう1つのデモンストレーションポイントでしょうか。
John L

7
エフェクトを使ったプログラミングの理想的な扱いについて、あなたが何を念頭に置いていますか?
Steven Shaw

6
素晴らしい記事をありがとう。データがプログラムの外部で発生する(たとえば、ファイルから読み取られる)依存型コードのいくつかの例を見て、そのような設定で値を型に昇格させる方法を理解してください。すべての例に、静的にサイズがわかっているベクトル(リストとして実装されている)が含まれているという感じです。
tibbe

4
@pigworkerあなたは神話として「位相区別なし」をとります(私が同意する他のものは神話です)。しかし、あなたはこれを私が見た論文や講演で解体していません。その間、私が尊敬する別の人は、「型チェック、コンパイル、および実行フェーズを意味のある形で分離できないため、依存型理論は典型的なコンパイラとは異なります。 」(2012年11月8日のAndrejの最新の投稿を参照)私の「偽造」の経験では、消去する必要はありませんが、少なくとも位相の区別がぼやけることがあります。ここではなくても、この問題について他に展開できますか?
sclv

4
@sclv私の仕事は特に「位相区別なし」の神話を対象にしていませんが、他の人は対象にしています。まず、ジェームズ・マッキンナとエドウィン・ブレイディによる「エピグラムの編集におけるフェーズの区別」という拒絶を、良い出発点としてお勧めします。しかし、Coqでのプログラム抽出に関する以前の作品も参照してください。タイプチェッカーによって行われるオープンターム評価は、MLへの抽出による実行とは完全に分離されており、抽出によってタイプと証明が取り除かれることは明らかです。
pigworker

20

依存型についてのもう1つの一般的な誤解は、Johnです。つまり、データが実行時にしか利用できない場合、それらは機能しません。getLineの例を以下に示します。

data Some :: (k -> *) -> * where
  Like :: p x -> Some p

fromInt :: Int -> Some Natty
fromInt 0 = Like Zy
fromInt n = case fromInt (n - 1) of
  Like n -> Like (Sy n)

withZeroes :: (forall n. Vec n Int -> IO a) -> IO a
withZeroes k = do
  Like n <- fmap (fromInt . read) getLine
  k (vReplicate n 0)

*Main> withZeroes print
5
VCons 0 (VCons 0 (VCons 0 (VCons 0 (VCons 0 VNil))))

編集:うーん、それは豚労働者の答えへのコメントであるはずでした。私は明らかにSOで失敗します。


最初の文は少し変わっているようです。依存型のポイントは、データが実行時にのみ利用可能であるときに機能することです。ただし、このCPSスタイルの手法は同じではありません。関数があるとしますVec Zy -> IO StringwithZeroesタイプZyはforall nで統一できないため、で使用することはできません。たぶん、1つまたは2つの特別なケースでそれを回避できますが、すぐに手に負えなくなります。
John L

単純に型付けされた値(getLineからの文字列など)を取り、それをより強力な型(上記のNatty nなど)に変換するときの鍵は、必要な動的チェックを行っていることを型チェッカーに納得させる必要があることです。あなたの例では、任意の数値を読み取っているので、forall nは理にかなっています。より正確な制限を同じ方法で実装できます。あなたはより良い例を持っていますかVec Zy(プログラムは、0ではなく5を入力するユーザーを処理する必要があります)?
ulfnorell 2012年

1
最初の文で言ったことは、外の世界とやり取りしてデータを取得する場合、依存型を使用できないと信じる人にときどき遭遇することです。私の要点は、あなたがしなければならない唯一のことは、通常は単純な、依存的に型付けされたパーサーを書くことです。
ulfnorell 2012年

1
ulfnorell:すみません、はっきりしていませんでした。で機能する関数とVec Zy -> IO Stringforの関数がありVec n -> IO String、型が一致する場合にのみ最初の関数を使用するとします。はい、それは可能ですが、それを有効にするメカニズムは不格好です。そして、これは非常に単純なロジックです。より複雑なロジックがある場合、それはさらに悪くなります。また、CPSで多くのコードを書き直す必要がある場合もあります。また、値レベルの用語に依存する型レベルの式はまだありません
John L

ああ、あなたの言っていることがわかります。これは、nに応じてさまざまなことを行うvReplicateのように、Nattyの目的です。実際、これは少し不格好なものになる可能性があります。CPSスタイルの代替手段は、パックされた実在物を処理することですzeroes :: IO (Some (Flip Vec Int))
ulfnorell

19

pigworkerは、なぜ依存型に向かわなければならないのかについて優れた議論をします。(a)それらは素晴らしいです。(b)彼らは実際にHaskellが既に行っていることの多くを単純化するでしょう。

「どうして?」も 質問、私が思うにいくつかのポイントがあります。最初のポイントは、依存型の背後にある基本的な概念は簡単です(型が値に依存できるようにする)一方で、その基本的な概念の影響は微妙で深遠です。たとえば、値とタイプの違いはまだ健在です。しかし、それらの違いを議論することは遠くなりますHindley--MilnerまたはSystem Fよりも微妙な違いがあります。これはある程度、依存型が根本的に難しい(たとえば、1次の論理が決定できない)ためです。しかし、もっと大きな問題は、何が起こっているのかを把握して説明するための適切な語彙がないということです。依存型について学習する人が増えるにつれ、語彙力が向上し、根底にある問題が依然として困難であっても、物事が理解しやすくなります。

2番目のポイントは、Haskellが成長しているという事実に関係しています依存型に向かって。私たちはその目標に向けて段階的に進歩しているのですが、実際にそこに到達することなく、段階的なパッチの上に段階的なパッチがある言語で立ち往生しています。新しいアイデアが普及するにつれ、同じようなことが他の言語でも起こりました。Javaは(パラメトリック)ポリモーフィズムを使用していませんでした。そして彼らが最後にそれを追加したとき、それは明らかにいくつかの抽象化リークと不自由なパワーを伴う漸進的な改善でした。結局のところ、サブタイピングとポリモーフィズムの混在は本質的に困難です。しかし、それがJava Genericsが機能する理由ではありません。古いバージョンのJavaに対する漸進的な改善という制約があるため、これらは従来どおりに機能します。ディット、OOPが発明され、人々が「目的」を書き始めたその時代にさかのぼって C(Objective-Cと混同しないでください)など。C++は、Cの厳密なスーパーセットであるかのように始まったことに注意してください。新しいパラダイムを追加するには、常に言語を新たに定義する必要があります。これらすべてについての私の要点は、真の依存型をHaskellに追加するには、ある程度の根拠と言語の再構築が必要になるということです。しかし、そのようなオーバーホールにコミットすることは本当に難しいですが、私たちが行ってきた漸進的な進歩は、短期的には安上がりに見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。C ++は、Cの厳密なスーパーセットであるかのように偽装して開始されました。新しいパラダイムを追加するには、常に言語を新たに定義する必要があります。そうしないと、複雑な混乱が生じます。これらすべてについての私の要点は、真の依存型をHaskellに追加するには、ある程度の根拠と言語の再構築が必要になるということです。しかし、そのようなオーバーホールにコミットすることは本当に難しいですが、私たちが行ってきた漸進的な進歩は、短期的には安上がりに見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。C ++は、Cの厳密なスーパーセットであるかのように偽装して開始されました。新しいパラダイムを追加するには、常に言語を新たに定義する必要があります。そうしないと、複雑な混乱が生じます。これらすべてについての私の要点は、真の依存型をHaskellに追加するには、ある程度の根拠と言語の再構築が必要になるということです。しかし、そのようなオーバーホールにコミットすることは本当に難しいですが、私たちが行ってきた漸進的な進歩は、短期的には安上がりに見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。または、いくつかの複雑な混乱に終わります。これに関するすべての私のポイントは、真の依存型をHaskellに追加するには、ある程度の根拠と言語の再構築が必要になるということです。しかし、そのようなオーバーホールにコミットすることは本当に難しいですが、私たちが行ってきた漸進的な進歩は、短期的には安上がりに見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。または、いくつかの複雑な混乱に終わります。これに関するすべての私のポイントは、真の依存型をHaskellに追加するには、ある程度の根拠と言語の再構築が必要になるということです。しかし、そのようなオーバーホールにコミットすることは本当に難しいですが、私たちが行ってきた漸進的な進歩は、短期的には安く見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。そのようなオーバーホールにコミットするのは本当に難しいですが、私たちが行ってきた漸進的な進歩は短期的には安く見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。そのようなオーバーホールにコミットするのは本当に難しいですが、私たちが行ってきた漸進的な進歩は短期的には安く見えます。本当に、GHCをハッキングする人はそれほど多くありませんが、存続させるために十分な量のレガシーコードがあります。これが、DDC、カイエン、イドリスなどのように多くのスピンオフ言語がある理由の一部です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.