您可以将类型类约束本质上视为隐式参数 - 即认为
Foo a => b
作为
FooDict a -> b
whereFooDict a
是类中定义的方法字典Foo
。例如,EqDict
将是以下记录:
data EqDict a = EqDict { equal :: a -> a -> Bool, notEqual :: a -> a -> Bool }
不同之处在于,每种类型的每个字典只能有一个值(对 MPTC 进行适当的概括),而 GHC 会为您填写其值。
考虑到这一点,我们可以返回您的签名。
type FooT m a = (MyMonad m) => ListT m a
foo :: MyType a -> MyOtherType a -> FooT m a
扩展到
foo :: MyType a -> MyOtherType a -> (MyMonad m => ListT m a)
使用字典解释
foo :: MyType a -> MyOtherType a -> MyMonadDict m -> ListT m a
这等效于将参数重新排序为
foo :: MyMonadDict m -> MyType a -> MyOtherType a -> ListT m a
这相当于字典变换的逆
foo :: (MyMonad m) => MyType a -> MyOtherType a -> ListT m a
这就是你要找的。
但是,在您的另一个示例中,情况并非如此。
type Bar a b = (Something a, SomethingElse b) => NotAsBar a b
bar :: Bar a b -> InsertTypeHere
扩展到
bar :: ((Something a, SomethingElse b) => NotAsBar a b) -> InsertTypeHere
这些变量仍然在顶层量化(即
bar :: forall a b. ((Something a, SomethingElse b) => NotAsBar a b) -> InsertTypeHere
),因为您在 的签名中明确提到了它们bar
,但是当我们进行字典转换时
bar :: (SomethingDict a -> SomethingElseDict b -> NotAsBar a b) -> InsertTypeHere
我们可以看到这不等于
bar :: SomethingDict a -> SomethingElseDict b -> NotAsBar a b -> InsertTypeHere
这会产生你想要的。
很难想出一个现实的例子,其中类型类约束被用在与量化点不同的地方——我在实践中从未见过它——所以这里有一个不切实际的例子,只是为了证明正在发生的事情:
sillyEq :: forall a. ((Eq a => Bool) -> Bool) -> a -> a -> Bool
sillyEq f x y = f (x == y)
对比如果我们==
在没有将参数传递给时使用 try 使用会发生什么f
:
sillyEq' :: forall a. ((Eq a => Bool) -> Bool) -> a -> a -> Bool
sillyEq' f x y = f (x == y) || x == y
我们得到一个错误的No 实例。Eq a
(x == y)
insillyEq
得到它的Eq
dict f
; 它的字典形式是:
sillyEq :: forall a. ((EqDict a -> Bool) -> Bool) -> a -> a -> Bool
sillyEq f x y = f (\eqdict -> equal eqdict x y)
退后一步,我认为您在这里感到恐惧的方式会很痛苦-我认为您只想使用某些东西来量化其上下文,其中上下文被定义为“使用它的函数签名”。这个概念没有简单的语义。您应该能够将其Bar
视为集合上的函数:它将两个集合作为参数并返回另一个集合。我不相信会有这样的功能供您尝试实现。
至于缩短上下文,您可以使用ConstraintKinds
允许您制作约束同义词的扩展,因此至少您可以说:
type Bars a = (Something a, SomethingElse a)
要得到
bar :: Bars a => Bar a b -> InsertTypeHere
但是你想要的仍然是可能的——你的名字不足以让我说出。您可能想研究Existential Quantification和Universal Quantification,这是对类型变量进行抽象的两种方式。
故事的寓意:记住这=>
就像->
除了那些参数是由编译器自动填充的,并确保您尝试定义具有明确定义的数学含义的类型。