未来就是现在,当你(使用GHC 8)上的一个标志开关或两个
Prelude> :set -XPolyKinds -XFlexibleInstances
让我们声明
Prelude> newtype Flip f a b = MkFlip (f b a)
,然后询问
Prelude> :kind Flip
Flip :: (k1 -> k -> *) -> k -> k1 -> *
Prelude> :type MkFlip
MkFlip
:: forall k k1 (b :: k) (f :: k -> k1 -> *) (a :: k1).
f b a -> Flip f a b
类型构造函数Flip
需要两个隐式参数,是k
和,以及三个显式参数,它们是产生一个类型的二元函数,然后是它的两个参数以相反的顺序。这个函数的参数是无约束的类型(如果他们喜欢,老人可以说“kind”),但它肯定会返回一个类型(严格意义上的“*
中的东西”,而不是毫无用处地模糊地指出“任何旧的垃圾权::
“),因为它肯定用作MkFlip
声明中的一种类型。
的数据构造,MkFlip
,需要隐含参数(的Flip
完全参数)和一个明确的说法,f b a
是一些数据。
发生什么事情是Hindley-Milner类型推理的一个级别。约束收集(例如,f b a
必须居住*
因为构造函数的参数必须居住f b a
),但除此之外,最一般的类型被传递:a
和b
可以是任何东西,所以它们的类型可以概括为和k
。
让我们玩同一游戏的不断类型构造:
Prelude> newtype K a b = MkK a
Prelude> :kind K
K :: * -> k -> *
Prelude> :type MkK
MkK :: forall k (b :: k) a. a -> K a b
我们看到,a :: *
但b
可以是任何旧垃圾(和为此事,k :: *
,因为这些天,* :: *
)。显然,a
实际上用作某种东西的类型,但根本不使用b
,因此不受约束。
我们可以再申报
Prelude> instance Functor (Flip K b) where fmap f (MkFlip (MkK a)) = MkFlip (MkK (f a))
,并要求
Prelude> :info Flip
...
instance [safe] forall k (b :: k). Functor (Flip K b)
告诉我们,未使用的b
仍然可以是任何旧的垃圾。因为我们有
K :: * -> k -> *
Flip :: (k1 -> k -> *) -> k -> k1 -> *
我们可以统一k1 = *
并获得
Flip K :: k -> * -> *
等
Flip K b :: * -> *
任何旧b
。 A Functor
实例因此是合理的并且实际上可交付的,其功能作用于打包的a
元素,对应于参数Flip K b
,其变为第一自变量K
,因此存储的元素的类型。
基于统一的类型推断仍然存在并且(相当)良好,正确的为::
。
我更新了我的问题。 –
“完全接地”是一个技术术语吗?我只听到完全应用。只是好奇... – Alec
@Alec:不,这是一个错误(对Prolog太多了:)) –