Prelude> :i ($)
($) ::
forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
(a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
與(a -> b) -> a -> b
有什麼不同?有沒有適合新型簽名的b
?
Prelude> :i ($)
($) ::
forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
(a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
與(a -> b) -> a -> b
有什麼不同?有沒有適合新型簽名的b
?
8.0之前,在typechecker中有一個特殊情況,使得$
的申請到未解除種類的工作。這也意味着你無法定義自己的功能,可以同時使用提升和未提升的類型。現在這個所謂的Levity Polymorphsim('輕量級'是指'某種東西被提升的程度'或'提升性',因爲'未提升'和'提升'類型)被嵌入到類型檢測器中,這是可能的:
import GHC.Exts (TYPE, RuntimeRep(..))
import Data.Kind (type (*))
ap :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b)
ap f x = f x
ap_LP :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b)
ap_LP f x = f x
乃至$
功能現在同樣定義爲ap_LP
,隨着typechecker不需要特殊的情況下,使$
工作與功能恢復未提升的類型(後面還有一個在typechecker的特殊情況,使多態應用,即runST $ ...
工作,但這與levity多態性無關)。這實際上是增加了複雜性的原因 - 現在類型系統中的「黑客」較少,GHC的用戶可以通過給函數適當的類型來利用輕量級多態性(請注意,從未推斷出輕量級多態類型,據我所知)。在輕量級多態性之前,如果您想編寫一個多態函數,可以在提取和未提取類型上工作,您有義務使用不同類型簽名編寫兩個相同的函數副本。
新類型從舊的不同點在於新的類型是比舊的嚴格更一般:
-- ok
ap' :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b)
ap' = ap_LP
-- type error:
-- * Couldn't match a lifted type with an unlifted type
ap_LP' :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b)
ap_LP' = ap
換句話說,每b
其中「適應」老標記必須(通過定義)符合新型簽名(所以這種改變完全向後兼容!)。
還要注意的是,以下是不可能:
ap'' :: forall (a :: TYPE r) (b :: *) . (a -> b) -> (a -> b)
ap'' f x = f x
產生的誤差是
A representation-polymorphic type is not allowed here:
Type: a
Kind: TYPE r
In the type of binder `x'
和SPJ解釋了限制here的原因:
($)的第二個參數不能有一個 取消裝箱的類型是絕對正確的。因爲($)的代碼必須圍繞 (傳遞給函數)移動該參數,所以它必須知道它的寬度,指針等。
但是實際上,將電話(f $ x)的結果解壓爲 就可以了,因爲($)的代碼不會混淆結果;它 只是尾調用f。
這就是說,不是每一個輕率多態性類型具有有效的居民 - 這涉及裝箱和盒裝類型之間的操作的區別,這隻能在某些情況下均勻的處理,並且typechecker確保的。
舊簽名是多年來的謊言。新的簽名實際上是更一般的,包括提升類型(kind *')和未提升類型(以前的'#';現在分成更多類型)。 – dfeuer
雖然不是一個完全重複的(我認爲這個問題可以從更新的答案中獲益),[這個答案](http://stackoverflow.com/a/35320729/465378)包含了一些可以幫助解釋事物的信息。 –
@sevo什麼語言的擴展打開了這個?我從其他一些討論中知道這一點,但無法觸發它。我只是得到'($)::(a - > b) - > a - > b' – Michael