我有一个这样定义的类型:
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
需要* -> *
)
答案 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