什么是多态/多类元组?

zer*_*one 9 haskell type-families polykinds

当我在做haskell-excercises问题时。我看到以下代码Constraint通过将每种类型应用于 Constraint 构造函数来创建聚合。在 GHC 中,Constraints 的深层嵌套元组似乎仍然是一种Constraint(也许是扁平化的?)。

{-# LANGUAGE DataKinds     #-}
{-# LANGUAGE PolyKinds     #-}
{-# LANGUAGE TypeFamilies  #-}
{-# LANGUAGE TypeOperators #-}


type family All (c :: Type -> Constraint) (xs :: [Type]) :: Constraint where
  All c '[] = ()
  All c (x ': xs) = (c x, All c xs)

-- >>> :kind! All
-- All :: (* -> Constraint) -> [*] -> Constraint
-- = All

-- >>> :kind! All Eq '[Int, Double, Float]
-- All Eq '[Int, Double, Float] :: Constraint
-- = (Eq Int, (Eq Double, (Eq Float, () :: Constraint)))
Run Code Online (Sandbox Code Playgroud)

我尝试使用PolyKinds扩展来概括它,如下所示。

{-# LANGUAGE DataKinds     #-}
{-# LANGUAGE PolyKinds     #-}
{-# LANGUAGE TypeFamilies  #-}
{-# LANGUAGE TypeOperators #-}


type family All' (c :: k -> r) (xs :: [k]) :: r where
  All' c '[] = ()
  All' c (x ': xs) = (c x, All' c xs)

-- >>> :kind! All'
-- All' :: (k -> r) -> [k] -> r
-- = All'

--- This one works. Tuples of Types is a Type.
-- >>> :kind! All' Maybe '[Int, Double, Float]
-- All' Maybe '[Int, Double, Float] :: *
-- = (Maybe Int, (Maybe Double, (Maybe Float, ())))

--- However this one gets stuck.
-- >>> :kind! All' Eq '[Int, Double, Float]
-- All' Eq '[Int, Double, Float] :: Constraint
-- = All' Eq '[Int, Double, Float]
Run Code Online (Sandbox Code Playgroud)

是种'(,) (a :: k) (b :: k)也是种k。往下看似乎不是这样,所以我想知道为什么All' c (x ': xs) = (c x, All' c xs)首先接受类型系列定义(考虑类型系列返回种类是r)?

?> :kind! '(,)
'(,) :: a -> b -> (a, b)
= '(,)

?> :kind! '(,) ('True :: Bool) ('False :: Bool)
'(,) ('True :: Bool) ('False :: Bool) :: (Bool, Bool)
= '( 'True, 'False)
Run Code Online (Sandbox Code Playgroud)

更新

正如@Daniel Wagner 已经在下面提到的,(,)这里使用的被认为是Type -> Type -> Type并且 kind 参数r被实例化到Type上面的第二个方程 ( All' c (x ': xs) = (c x, All' c xs)) 中。事实上,如果我们使用了'(,),它会正确地返回一个类型错误。我能够使用本博客文章中描述的技术进一步确认它如下(All'用 kindk和实例化*):

?> :set -fprint-explicit-kinds
?> :info All'
type All' :: forall k r. (k -> r) -> [k] -> r
type family All' @k @r c xs where
  forall k (c :: k -> *). All' @k @(*) c ('[] @k) = ()
  forall k (c :: k -> *) (x :: k) (xs :: [k]).
    All' @k @(*) c ((':) @k x xs) = (c x, All' @k @(*) c xs)
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 6

这里有一个句法双关语。实际上有几种不同的逗号,具有不同的种类:

 (,) :: Type -> Type -> Type
 (,) :: Constraint -> Constraint -> Constraint -- ...ish
'(,) :: a -> b -> (a, b)
Run Code Online (Sandbox Code Playgroud)

请注意,这些种类中没有一种与其他任何一种统一。此外,第二个有点撒谎。if x :: Constraintand y :: Constraint, then (x, y) :: Constraint,但逗号不能像 in 那样加前缀(,) x y

当试图消除前两个歧义时,GHC 假定您正在使用,(,) :: Type -> Type -> Type除非您在语法上不能使用它的地方(例如在 an 的左侧=>),或者您已经给出了 的明确种类注释:: Constraint。单勾'消除了前两个和最后一个之间的歧义。

  • 我希望如果早期的 Haskell 委员会预见到我们会在某个时候拥有 `DataKinds`,他们就会抛弃 `(Num a, Eq a)` 表示法,而可能会改为 `(&) :: Constraint -> Constraint -> Constrained` 什么的。 (3认同)