[英]How to apply polymorphic function to a concrete type?
下面是我在學習 Haskell 時遇到的一個問題的提煉版本:
data A = A
data B = B
data Test = TestA A
| TestB B
test :: (a -> a) -> (Test -> Test)
test op t =
case t of
TestA a -> TestA $ op a
TestB b -> TestB $ op b
testA = test id (TestA A)
testB = test id (TestB B)
嘗試編譯它會出現以下錯誤:
無法將預期類型“B”與實際類型“a”匹配
'a' 是由 test :: (a -> a) -> Test -> Test 的類型簽名綁定的剛性類型變量
這是怎么回事? 我認為當我傳入一個多態函數時,我應該能夠將它應用於不同具體類型的值。
這里的基本問題是 Haskell 如何從類型簽名中的自由變量推斷量化。 鑒於以下類型簽名...
test :: (a -> a) -> (Test -> Test)
...類型變量a
未綁定。 Haskell 自動將未綁定的類型變量轉換為通用量化約束,所以上面的類型實際上是這樣解釋的:
test :: forall a. (a -> a) -> (Test -> Test)
現在你得到的錯誤可能更有意義——類型變量a
每次調用test
只能與一種類型統一,這是由調用者決定的。 因此, (a -> a)
函數可以是String -> String
或Int -> Int
或任何其他類型,但它永遠不能是同時適用於A
和B
的函數。
但是,很明顯,當您編寫該類型簽名時,您有不同的意圖。 您希望(a -> a)
函數成為類似於id
的類型簽名:一個真正適用於任何值的函數,而不是某個特定選擇的特定函數a
。 要指定這一點,您必須使forall
顯式,以便編譯器准確地知道該類型變量應如何量化:
test :: (forall a. a -> a) -> (Test -> Test)
但是,上述類型實際上在標准 Haskell 中無效。 它是由GHC支持,但是,通過使用Rank2Types
或RankNTypes
擴展,這允許“較高等級”多態性像上述類型簽名。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.