Haskell组合了多个类型类约束

Haskell组合了多个类型类约束,haskell,type-families,Haskell,Type Families,我想知道我如何才能使上述工作。现在我知道我可以手动需要两个类型类,但我希望能够任意组合任意数量的类型类 现在我知道在这种情况下要求Num是没有意义的,但这只是一个例子。您需要定义一个typeclass(因为typeclass可以部分应用),它通过一个超类简化为您想要的约束: {-# LANGUAGE TypeFamilies #-} import GHC.Prim import qualified Data.Set as Set class Functor' f where type

我想知道我如何才能使上述工作。现在我知道我可以手动需要两个类型类,但我希望能够任意组合任意数量的类型类


现在我知道在这种情况下要求
Num
是没有意义的,但这只是一个例子。

您需要定义一个typeclass(因为typeclass可以部分应用),它通过一个超类简化为您想要的约束:

{-# LANGUAGE TypeFamilies #-}

import GHC.Prim
import qualified Data.Set as Set

class Functor' f where
    type FConstraint f :: * -> Constraint
    fmap' :: (FConstraint f a, FConstraint f b) => (a -> b) -> f a -> f b

instance Functor' Set.Set where
    type FConstraint Set.Set = Ord Num  --error here, won't let me put Num
    fmap' = Set.map
显然
(f&g)x
保持iff
f x
gx
保持。
FConstraint'
的定义现在应该很明显:

{-# LANGUAGE 
    PolyKinds, UndecidableInstances, TypeOperators
  , MultiParamTypeClasses, ConstraintKinds, TypeFamilies
  , FlexibleContexts, FlexibleInstances 
#-}

class (f x, g x) => (&) f g (x :: k)
instance (f x, g x) => (&) f g x

看起来我需要做的唯一更改不是部分应用
FConstraint

class Functor' ... 

instance Functor' Set.Set where
    type FConstraint Set.Set = Ord & Num
    fmap' f = Set.map ( (+1) . f )  -- (+1) to actually use the Num constraint

不幸的是,据我所知,这不允许我使用具体的类型,但我认为这在种类级别上甚至与Functor不匹配(
Functor
具有种类
*->*
,但是一个具体值的列表,例如
String
具有种类
*
)问题是,
Ord
是一个类,
Num
也是一个类。因此,
ordnum
是一个格式错误的约束。如果您想同时使用
Ord
Num
约束
type
,那么它应该类似于
Ord-type
Num
@Bakuriu,我明白您的意思,我不希望
Ord-Num
按原样工作,但我尝试了类似
(Ord a,Num a)的变体=>一个
但都无法运行,我今天要尝试更多的东西,看看是否能找到一个运行的。我尝试复制了你写的东西,但最终需要打开很多扩展:
{-#LANGUAGE ConstraintKinds,FlexibleContext,MultiparamTypeClass,PolyKinds,TypeFamilies,TypeOperators,UndedicatableInstances#-}
即使如此,它仍然告诉我,
表达式中使用“fmap”(+1)所产生的(&)Ord Num b0没有实例
@semicolon我无意中发现了一行。现在应该修复了。我现在得到了“(&)f g x”(所有实例类型必须是(T a1…an)形式的非法实例声明,其中a1…an是*不同的类型变量*,并且每个类型变量最多出现一次
{-# LANGUAGE TypeFamilies #-}

import GHC.Prim
import qualified Data.Set as Set

class Functor' f where
    type FConstraint f a :: Constraint
    fmap' :: (FConstraint f a, FConstraint f b) => (a -> b) -> f a -> f b 

instance Functor' Set.Set where
    type FConstraint Set.Set a = (Ord a, Num a)
    fmap' f = Set.map ((+ 1) . f)

foo = fmap (+ 1) $ Set.fromList [1, 2, 3]