したがって、イドリスでは、次のように書くことは完全に有効です。
item : (b : Bool) -> if b then Nat else List Nat
item True = 42
item False = [1,2,3] // cf. https://www.youtube.com/watch?v=AWeT_G04a0A
型署名がないと、これは動的に型付けされた言語のように見えます。しかし、確かに、Idrisは依存型です。 item b
の具体的なタイプは、実行時にのみ決定できます。
もちろん、これはHaskellプログラマーの話です。Idrisの意味でのitem b
のタイプはコンパイル時に与えられ、それはif b then Nat ...
です。
さて、私の質問です。Haskellでは、ランタイムとコンパイル時の境界は、値の世界(False、 "foo"、3)と型の世界(Bool、String、Integer)の間で正確に実行されると結論付けるのは正しいですか? Idrisでは、ランタイムとコンパイル時間の境界は宇宙を越えていますか?
また、Haskellの依存型(DataKindsとTypeFamiliesを使用、 この記事 を参照)でも、HaskellはIdrisとは反対に値を許可しないため、上記の例はHaskellでは不可能であると仮定するのは正しいですか?タイプレベルにリークしますか?
はい、Idrisでの型と値の区別が、コンパイル時のみの区別と実行時とコンパイル時の区別と一致していないことに注意してください。それはいいことだ。プログラムロジックの場合と同様に、仕様でのみ使用される「ゴースト変数」があるのと同様に、コンパイル時にのみ存在する値があると便利です。実行時に型表現を用意して、データ型のジェネリックプログラミングを可能にすることも役立ちます。
Haskellでは、DataKinds
(およびPolyKinds
)で
type family Cond (b :: Bool)(t :: k)(e :: k) :: k where
Cond 'True t e = t
Cond 'False t e = e
そして、それほど遠くない将来に、私たちは書くことができるでしょう
item :: pi (b :: Bool) -> Cond b Int [Int]
item True = 42
item False = [1,2,3]
しかし、そのテクノロジーが実装されるまでは、次のような依存関数タイプのシングルトン偽造を処理する必要があります。
data Booly :: Bool -> * where
Truey :: Booly 'True
Falsey :: Booly 'False
item :: forall b. Booly b -> Cond b Int [Int]
item Truey = 42
item Falsey = [1,2,3]
あなたはそのような偽物でかなり遠くまで行くことができます、しかし私たちが本物を持っていればそれはすべてはるかに簡単になるでしょう。
重要なことに、Haskellの計画は、forall
とpi
を維持および分離し、それぞれパラメトリック多相性とアドホック多相性をサポートすることです。 forall
に付随するラムダとアプリケーションは、今と同じようにランタイムコード生成で消去できますが、pi
のものは保持されます。また、実行時型の抽象化pi x :: * -> ...
を使用して、Data.Typeable
である複雑さのネズミの巣をゴミ箱に捨てることも理にかなっています。
今私の質問:Haskellでは、ランタイムとコンパイル時の境界は、値の世界(False、 "foo"、3)と型の世界(Bool、String、Integer)の間で正確に実行されると結論付けるのは正しいですか? Idrisでは、ランタイムとコンパイル時間の境界は宇宙を越えていますか?
Idrisは Epic にコンパイルされます (更新:いいえ、Spearmanが以下のコメントで述べているように、Episにコンパイルされなくなりました):
名前がスコープ内にあるかどうかを確認する以外に、セマンティックチェックはありません---高水準言語が型チェックを実行したと想定されます。いずれの場合も、Epicは高水準型システムまたはユーザーが行った変換について想定しないでください。適用されます。型の注釈は必須ですが、コンパイラーにヒントを与えるだけです(これを変更する可能性があります)。
したがって、タイプは表記上重要ではありません。つまり、用語の意味はそのタイプに依存しません。さらに、いくつかの値レベルのものを消去することができます。 in Vect n A
(ここで、Vect
は静的に既知の長さのリストのタイプです)n
(長さ)は消去できます なぜなら
Brady、McBride、McKinnaによって BMM04 で説明されている方法があり、データ構造からインデックスを削除し、それらを操作する関数がすでに適切なインデックスのコピーを持っているか、インデックスをすばやく作成できるという事実を利用しています必要に応じて再構築。
ここで重要なのは、Idrisのpi
はHaskellのforall
とほぼ同じように型に対して機能するということです。この場合、両方ともパラメトリックです(ただし、これらのパラメトリックは異なります)。コンパイラーは型を使用してコードを最適化できますが、どちらの言語でも制御フローは型に依存しません。つまり、if A == Int then ... else ...
とは言えません(ただし、A
が正規形式の場合は、 Int
であるかどうかを静的に認識しているため、 can write A == Int
ですが、すべての決定は実行前に行われるため、制御フローには影響しません)。 item b
の具体的なタイプは、実行時には問題になりません。
ただし、 pigworker が言うように、型がパラメトリックである必要はありません。また、必ずしも値がノンパラメトリックである必要はありません。タイプレベル—値レベルとパラメトリック—ノンパラメトリックは完全に直交する二分法です。詳細については、 this answerを参照してください。
したがって、HaskellとIdrisは、ランタイム/コンパイルコンテンツでの値レベルのものの処理方法が異なります(Idrisでは、引数を.
でマークして消去可能にすることができるため)が、型はほぼ同じ方法で処理されます。