2012-02-15 41 views
52

我知道什麼類型的協方差和逆變。我的問題是爲什麼我在研究Haskell(與Scala相反)時還沒有遇到這些概念的討論?爲什麼沒有關於Haskell(與Scala或C#相反)中的共同和反對方差的討論?

Haskell視圖類型與Scala或C#相比有一個根本性的區別,我想闡明它們之間的區別。

或者,也許我錯了,我只是還沒有學會足夠的哈斯克爾尚未:-)

+2

這已經有一段時間了,但我似乎記得這段視頻中關於co/contra-variance的一些函數/ haskellish對話框:http://channel9.msdn.com/shows/Going+Deep/E2E-Brian-Beckman-and -Erik-Meijer-CoContravariance-in-Physics-and-Programming-2-of-2/ – steamer25 2012-02-16 19:43:02

回答

58

主要有兩個原因:

  • 哈斯克爾缺乏亞型的固有概念,所以一般差異不太相關。
  • 約定變異主要出現在涉及可變性的地方,因此Haskell中的大多數數據類型都只是協變的,並且顯式地區分它們幾乎沒有任何價值。

但是,這些概念確實適用 - 例如,fmapFunctor實施的提升操作實際上是協變的;在類別理論中使用術語co-/contravariance來討論函子。 contravariant package爲逆變函數定義了一個類型類,如果你看一下實例列表,你會看到爲什麼我說它不太常見。

也有地方的想法隱含顯示出來,如何手動轉換工作 - 各種數字型類定義的轉換和從基本類型,如IntegerRational,模塊Data.List包含的一些標準功能的通用版本。如果你看看the types of these generic versions,你會看到Integral限制(給出toInteger)用於逆變位置類型,而Num約束(給出fromInteger)用於協變位置。

+7

我認爲逆變與可變性之間沒有關係。事實上,可變性導致不變性。反變換的例子是函數輸入,'Ord'和'Eq'(當然是它們的等價物),其中沒有一個甚至有數據要被突變。 – 2012-02-16 17:08:55

+13

@ DanielC.Sobral:寫入一個可變引用是逆變的,是函數輸入的特例。因此,儘管簡單的數據類型通常允許協變性,但允許逆變的類型往往表示匯或輸出,除非涉及某種副作用,否則這些類型可能是微不足道的。不過,讀取和寫入操作的可變引用必然是不變的。 – 2012-02-16 18:06:25

+0

@丹尼爾與可變性相關的逆變可以在[with function]中看到(http://hackage.haskell.org/packages/archive/snap/0.7/doc/html/Snap-Snaplet.html#v:with)提供通過Snap Framework的Snaplet API。它的設計恰恰是爲了讓「易變」狀態的層級能夠被輕鬆操縱。 – mightybyte 2012-02-16 18:09:21

21

Haskell中沒有「子類型」,所以協變和逆變都沒有任何意義。在斯卡拉,你有例如Option[+A]與子類Some[+A]None。你必須提供協方差註釋+來說Option[Foo]Option[Bar] if Foo extends Bar。由於子類型的存在,這是必要的。

在Haskell中,沒有子類型。在哈斯克爾Option等效,叫Maybe,有這樣的定義:

data Maybe a = Nothing | Just a 

類型變量a永遠只能是一個類型的,所以它沒有進一步的信息是必要的。

6

如上所述,Haskell沒有子類型。但是,如果您正在查看類型類,可能不清楚如何在沒有子類型的情況下工作。

類型類指定類型的謂詞,而不是類型本身。所以當Typeclass有一個超類(例如Eq a => Ord a)時,並不意味着實例是子類型,因爲只有謂詞是繼承的,而不是類型本身。

另外,co-,contra-和in-variance在數學的不同領域意味着不同的東西(參見Wikipedia)。例如,在函數中使用了協變和逆變這兩個術語(這反過來在Haskell中使用),但這些術語意味着完全不同的東西。術語不變式可以在很多地方使用。

相關問題