我有一个这样定义的类型:
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
需要* -> *
)
不,这是不可能的。高等级类型的重点是处理任何参数类型。而PrimeSet
根本不是真正的参数 - 基本上,它始终是PrimeSet Integer
。为什么你有这个a
参数?
然而,对于“有点容器”的类型有一个不同的类,但不是任意类型: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
另一种方法是你实际上使用参数化类型,仿函数,但不是所有Haskell类型的普通Hask类别,而只是在类型的子类别中
小号
是
是Integer
。我有这样一个类in my constrained-categories package。但是,特别是对于这种类型,这似乎没有任何意义。
您可以使用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(和monofoldable类)来概括一点:
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