是否可以对种类较高的类型的类实例实施类型约束?

时间:2019-04-18 16:48:04

标签: haskell typeclass type-constraints higher-kinded-types

我有一个这样定义的类型:

newtype PrimeSet a = P Integer
    deriving Eq

我还定义了一个函数,可以将素数集转换为列表,前提是其类型参数为Integral

toList :: Integral a => PrimeSet a -> [a]

我现在要给PrimeSet一个Foldable实例,所以这是我的第一次尝试(从fold导入Data.Foldable后):

instance Foldable PrimeSet where
    foldMap f = fold . map f . toList

但是,这不起作用,编译器告诉我Could not deduce (Integral a) arising from a use of ‘toList’。我对这条消息的理解是,toList要求其参数为Integral a => PrimeSet a类型,但在Foldable实例中不一定是这种情况。

该消息还说,一个可能的解决方法是将Integral a实现的类型签名上下文中添加foldMap,但是当然然后我被告知不允许这样做。除非我使用InstanceSigs,否则请为类方法提供我自己的类型定义,所以我尝试了这一点,但这似乎也不起作用。

所以我的问题是这样的:如果我正在编写该类实例的类型的类型参数被隐藏,是否可以向该类实例添加类型约束?或者可以重申一下,我可以这样做吗? ?

instance (Integral a) => Foldable (PrimeSet a) where

(这当然不起作用,因为PrimeSet a的类型为*,而Foldable需要* -> *

2 个答案:

答案 0 :(得分:3)

否,这是不可能的。更高种类的类型的全部要点是要处理 any 参数类型。 PrimeSet根本不是参数化的-基本上,它总是 PrimeSet Integer。为什么根本没有那个a参数?

但是,对于“ kinda容器”类型有一个不同的类,但对于任意类型则没有:MonoTraversable,或者在这种情况下实际上是MonoFoldable

{-# LANGUAGE FlexibleInstances, TypeFamilies #-}

import Data.MonoTraversable

type instance Element (PrimeSet a) = a
-- or, if `PrimeSet` is not parameterised,
-- type instance Element PrimeSet = Integer

instance (Integral a) => MonoFoldable (PrimeSet a) where
  otoList = YourImplementation.toList

另一种选择是,您确实使用了参数化类型,实际上是函子,但不是在 all Haskell类型的常规 Hask 类别中,而是仅在其类型的子类别中使用 s are Integer。我有这样的课程in my constrained-categories package。但是,尤其对于这种类型的人,这似乎毫无意义。

答案 1 :(得分:2)

您可以使用GADT约束参数类型:

{-# LANGUAGE GADTs #-}

data PrimeSet a where
    PrimeSet :: Integral a => Integer -> PrimeSet a

instance Foldable PrimeSet where
    foldr f b (PrimeSet x) = f (fromInteger x) b

您可以使用ConstraintKinds(和可折叠类)进行概括:

data Monomorphic f c a where
    Monomorphic :: c a => f -> Monomorphic f c a

instance (item ~ Item f, MonoFoldable f) => Foldable (Monomorphic f ((~) item)) where
    foldr f b (Monomorphic xs) = ofoldr f b xs

data PrimeSet = PrimeSet Integer

instance Foldable (Monomorphic PrimeSet Integral) where
    foldr f b (Monomorphic (PrimeSet i)) = f (fromInteger i) b