Flip 数据类型的函子类型变量

Functor type variables for Flip data type

我有以下类型定义:

newtype Flip f a b = 
  Flip (f b a) deriving (Eq, Show)

Flip 数据构造函数有一个或三个参数吗?

考虑以下实施:

data K a b = K a

newtype Flip f a b = 
  Flip (f b a) deriving (Eq, Show)

instance Functor (Flip K a) where
  fmap f (Flip (K b)) = Flip (K (f b))  

(Flip K a) 的类型是什么?

Flip 数据构造函数有 一个参数。该参数的类型为 f b a.

这意味着 f 本身是类型为 f :: * -> * -> * 的高阶类型参数。更严格的 newtype 语句是:

newtype Flip (f :: * -> * -> *) a b = Flip (f b a)

因此,您可以实例化一个 Flip Either Int Bool,因为 Either 是一个需要两个额外类型参数的类型,然后构造一个 Flip (Right 1) :: Flip Either Int Bool.

What is the type of (Flip K a)?

Flip K a 不是完全应用的类型。在伪代码中,它的类型是b -> Flip K a b。一旦 b 被解析(Functor 适用于高阶类型),我们知道 Flip 的唯一参数将有一个 K b 构造函数。因此,例如 Flip (K 1)Flip K a Int 类型。

未来就是现在,当您(使用 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

type 构造函数 Flip 接受两个隐式参数,即 kk1,以及三个显式参数,即二元函数生成一个类型,然后以相反的顺序生成它的两个参数。这个函数的参数是unconstrained类型的(老人们喜欢可以说"kind"),但肯定是returns类型(严格意义上的"thing in *",而不是无用的"any old rubbish right of ::") 的模糊意义,因为它肯定在 MkFlip.

的声明中用作类型

data 构造函数 MkFlip 采用 5 个隐式参数(正是 Flip 的参数)和一个显式参数,是 f b a.

中的一些数据

正在进行的是 Hindley-Milner 类型推理的上一层。收集约束(例如,f b a 必须位于 *,因为构造函数参数必须位于 f b a),否则会提供最通用的类​​型:ab可以是任何东西,所以它们的类型被概括为 k1k.

让我们用常量类型构造函数玩同样的游戏:

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。因此,一个 Functor 实例是合理的,并且确实是可交付的,函数作用于打包的 a 元素,对应于 Flip K b 的参数,成为 first K 的参数,因此是存储元素的类型。

基于统一的类型推断仍然存在并且(相当)好,::