2015-09-23 13 views
16

型チェッカーを渡す関数定義の次の対を、検討しますタイプforall a. aの表現は、タイプIntの1つが予想される場合に使用できます。これはサブタイピングに似ているようですが、Haskellの型システムにはサブタイプがないと主張されています。これらの代替可能性の形式はどのように異なるのですか?なぜフォーオールですか? Intのサブタイプとは見なされませんが、forall型の式を使用できます。 Int型のどこでも期待されていますか?</p> <pre><code>a :: forall a. a a = undefined b :: Int b = a </code></pre><p>即ち:

この質問は、forall a. aに特定されていません。その他の例としては、以下が挙げられる:

id :: forall a. a -> a 
id x = x 

idInt :: Int -> Int 
idInt = id 
+0

'定義されていません 'は*サブタイプではありません。エラーです。なぜあなたはこれがサブタイピングだと思いますか? – AJFarmar

+4

これは別の例です: 'mempty :: forall m。 Monoid m => m'、 'let x = mempty :: [Int]'とする。 – rampion

+0

しかし、私は注意をそらしています。本当にここで起こっているのは、 'forall a。 aはbottomと同じです(https://wiki.haskell.org/Bottom)。 - bottomはすべての型の住人です(ただし、unboxed型の型に関するいくつかの注意点がありますが)。そのタイプはそうです。 – rampion

答えて

14

型付きラムダ計算では、通常、:と表示されるか、またはハスケルで::と表示されます。一般的に、関係は「多対多」なので、型は複数の値を含むことができ、値も多くの型を持つことができます。

特に、多型システムでは、値に複数の型を持たせることができます。このようなタイプのシステムの例

map :: (a -> b) -> [a] -> [b] 

map :: (Int -> Int) -> [Int] -> [Int]. 

ことが意味「より一般的なタイプ」、type orderと種類に関係を定義するために(時々)が可能です。 t ⊑ sならばtsよりも一般的であり、M : tならばM : sであり、そのようなタイプのシステムのタイピング規則はそれを正確に推論することを意味する。または、stの特殊化です。したがって、この意味で、型にはsubtypingの関係があります。

しかし、我々はオブジェクト指向言語でサブタイピングについて話すとき、私たちは通常nominal subtypingを意味し、つまり、私たちは、クラスの継承を定義するときのように、種類は何のサブタイプであるを宣言。 Haskellでは、宣言とは無関係に、型のプロパティです。たとえば、任意のタイプはforall a . aの特殊化です。型推論とどれが最も関数型言語のためのベースであることができHindley-Milner type systemについて

は、principal typeの概念がある:式Mは(任意)タイプを有する場合、それはまた、その主要型を有し、かつプリンシパルタイプは、Mのすべての可能なタイプの中で最も一般的なタイプです。重要な特徴は、HM型推論アルゴリズムが常に最も一般的な型を見つけることである。したがって、最も一般的で推論されたプリンシパルタイプは、有効なタイプのMに特化できます。

+0

't⊑s'は、' t'がより一般的ではなく 's'よりも特異的であることを意味しませんか? – dfeuer

+0

@dfeuer私はWikipedia [HM on page](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#Polymorphic_type_order)と同じ表記を使用しました。ここで、⊑は「より一般的」を意味します。ページが間違っている可能性があります:)。 –

+0

あなたは「M:t」ならば「M:s」も意味するように書いています。私は間違っている可能性があります。 – dfeuer

2

それはサブタイプではないです、それはb = atype unification!

a :: forall a. a 
a = undefined 

b :: Int 
b = a 

だ、我々は同じタイプであることをbaを制約しているので、コンパイラはそれが可能であることを確認します。 aの型はforall a. aであり、これは定義によってすべての型と統一されているため、コンパイラは私たちの制約に従います。 f :: (a -> Int) -> agがどのので、bbIntでなければならない必要があり、a -> Int(String -> b) -> bで統一しなければならないことを意味タイプa -> Intを、持っていなければならないことを意味し、統一を歩い

f :: (a -> Int) -> a 
g :: (String -> b) -> b 
h :: String -> Int 
h = f g 

タイプの統一も、私たちのようなものを行うことができますコンクリートタイプ(String -> Int) -> Intgとする。これは、aString -> Intであることを意味する。

a -> Int(String -> b) -> bも他のサブタイプではありませんが、(String -> Int) -> Intとして統一できます。

+0

この回答がどのように質問に対処しているのかわかりません: "なぜ*なぜ*は、Intのサブタイプと見なされないのですか?" –

+3

@DominiqueDevriese主な理由は、タイプではないということでしょうか? – Cubic

+1

@Cubic:タイプではないものは何ですか? 'forall a。 a'と 'Int'は明らかに型ですよね? –

3

:: aとは、「任意のタイプ」を意味しますが、サブタイプは意味しません。 aIntBool、またはIO (Maybe Ordering)となる可能性がありますが、特にそれはありません。 aは正確にタイプではなく、タイプ変数です。

は、我々はこのような機能を持っているとしましょう:

id x = x 

コンパイラは、私たちの引数xのための特定のタイプが存在しないことを理解しています。私たちはのタイプをxに使用することができます。それはidから出てくるものと同等である限りです。署名を以下のように書く:

-- /- Any type in... 
-- | /- ...same type out. 
-- V V 
id :: a -> a 

タイプはHaskellの大文字で始まることに注意してください。これは型ではありません:型変数です!

私たちは多型を使用する方が簡単だからです。

(>>>) :: (Bool -> Int) -> (Int -> String) -> (Bool -> String) 
(>>>) f g a = g (f a) 

(>>>') :: (Ordering -> Double) -> (Double -> IO()) -> (Ordering -> IO()) 
(>>>') f g a = g (f a) 

(>>>'') :: (Int -> Int) -> (Int -> Bool) -> (Int -> Bool) 
(>>>'') f g a = g (f a) 

-- ...and so on. 

:私たちは、このようにすべてのタイプを書かなければならなかった場合

plusOneTimesFive :: Int -> Int 
plusOneTimesFive = (+1) >>> (* 5) 

reverseHead :: [Bool] -> Bool 
reverseHead = reverse >>> head 

しかし、どのような:

(>>>) :: (a -> b) -> (b -> c) -> (a -> c) 
(>>>) f g a = g (f a) 

だから私たちはのようなものを書くことができます:例えば、組成物は、便利なアイデアですそれはただばかだ。

ので、コンパイラはそうのようなタイプの統一を使用してタイプを推測:

はのはGHCiのにI入力にこのことを言ってみましょう。ここでは簡略化のためをIntとしましょう。

id 6 

コンパイラは考えて:id 6 :: Intので、id :: a -> a」、そしてそれがIntを渡されていますので、a = Int

これはないサブタイプであるサブタイピングは、型クラスを使用して取得することができますが、これは基本的な多型です。

+1

私はあなたが間違っていると思う、これはサブタイプではない。下の私の答えを見てください。 –

11

このような質問で、私は元に戻って、基本的には、ハスケルの設計の基礎をなす数学的理論は、System Fがないサブタイプのncept。

はい、Haskellのサーフェス構文を見て、何かのタイプの式がT'と予想されるどんなコンテキストでも使用できるようなケースがあることに気付くことができます。しかし、Haskellはサブタイプをサポートするように設計されているため、これは発生しません。むしろ、HaskellはSystem Fの忠実なレンダリングよりもユーザーフレンドリーに設計されていたという事実の事故として発生します。

この場合、型レベルの量指定子は一般的にHaskellコードでは明示的に書かれておらず、型レ​​ベルlambdasとアプリケーションは決してであるという事実と関係がある。システムFの角度からタイプforall a. aを見ると、Intコンテキストへの代入可能性はなくなります。 a :: forall a. aは型レベル関数であり、Intが必要なコンテキストでは使用できません。Intに最初に適用してa Int :: Intを取得する必要があります。Intコンテキストで実際に使用できるものです。 Haskellの構文は、使いやすさという意味でそれを隠していますが、それは基本的な理論にあります。

要するに、Haskellをどのコンテキストタイプに置き換えることができ、どの種類の暗号 - サブタイプ関係があるのか​​を示すことによって、Haskellを分析することができますが、それは実際には効果がありません。設計の電流。それは意図や他の人的要因のように、技術的な問題ではありません。

+1

多型型システム(すなわち、ハスケルの近親者)のいくつかの形式化は、実際にサブタイプの一形態としてより多型的な関係をモデル化することに注意する価値がある。参照の例については私の答えを見てください。 –

+0

GHCは、基本的な理論としてSystem Fバリアントを使用していますが、これはHaskellタイプのシステムには見られません。 @DominiqueDevrieseの言い回しの言葉が代わりに使われてもいいかなと思う。 – dfeuer

+0

@dfeuer "コア言語"(GHCのSystem F拡張と比較して "タイプアノテーションを動作させる"の2種類)は、スコープ/目的が異なります。前者には型推論の形式が含まれています。たとえば、 'forall a。 a'は 'Int'が必要なところで使うことができます。 GHCのSystem Fの子孫は 'forall a。 a'値を 'Int'sに変換します。型推論が最初に必要な型のアプリケーション/抽象クラスを追加したとき、言語のみがHaskellをモデル化します。型推論をモデル化しないことは、アプリケーションに応じて長所と短所があります。 –

5

タイプforall a. aのタイプは、Intが期待されているどこにでも使用でき、これは2つのタイプ間のサブタイプの関係を意味するとします。上記の他の答えは、この "多型よりも"相関がサブタイプではないことをあなたに説得しようとします。しかし、典型的なオブジェクト指向言語で見られるサブタイプの形式とは確かに異なるが、これは「多型よりも高い」相関がサブタイプの(異なる)形式とみなされることを意味しない。実際に、多型型システムのいくつかの形式化は、そのサブタイプ関係においてこの関係を正確にモデル化する。これは、例えばOderskyとLäuferの論文"Putting type annotations to work"のタイプシステムの場合です。

+0

私はそれをサブタイプと呼んでいると誤解を招くと思います。真の意味でのOOPスタイルのサブタイプではありません。その論文は確かに興味深いものですが。 – AJFarmar

+0

私は同意しません。つまり、OOPスタイルのサブタイプよりもサブタイプ化が多いという点です。 –

関連する問題