使用具有等式约束的 Data.Constraint.Forall
Using Data.Constraint.Forall with equality constraints
假设我有这样一个函数:
{-# LANGUAGE ScopedTypeVariables #-}
class C a where
foo :: forall f a b. (C (f a), C (f b)) => f a -> f b
foo = _
现在,如果我想将 a
和 b
的范围移动到 foo
类型中类型类约束的右侧(比方说,因为我想使用 foo
实现需要在 a
和 b
中多态的类型类方法),它可以使用 Data.Constraint.Forall
:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds, TypeOperators #-}
import Data.Constraint
import Data.Constraint.Forall
foo' :: forall f. (ForallF C f) => forall a b. f a -> f b
foo' = helper
where
helper :: forall a b. f a -> f b
helper = case (instF :: ForallF C f :- C (f a)) of
Sub Dict -> case (instF :: ForallF C f :- C (f b)) of
Sub Dict -> foo
现在,我的问题是,假设我将函数更改为涉及类型等式的内容:
{-# LANGUAGE TypeFamilies, ScopedTypeVariables #-}
type family F a :: * -> *
bar :: forall f g a b. (F (f a) ~ g a, F (f b) ~ g b) => f a -> f b
bar = _
有没有办法使上述技术适应这种情况?
这是我尝试过的:
{-# LANGUAGE TypeFamilies, ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds, TypeOperators #-}
import Data.Constraint
import Data.Constraint.Forall
type F'Eq f g x = F (f x) ~ g x
bar' :: forall f g. (Forall (F'Eq f g)) => forall a b. f a -> f b
bar' = helper
where
helper :: forall a b. f a -> f b
helper = case (inst :: Forall (F'Eq f g) :- F'Eq f g a) of
Sub Dict -> case (inst :: Forall (F'Eq f g) :- F'Eq f g b) of
Sub Dict -> bar
但是(不出所料)这失败了,因为不饱和类型同义词:
Type synonym ‘F'Eq’
should have 3 arguments, but has been given 2
In an expression type signature: Forall (F'Eq f g) :- F'Eq f g a
In the expression: (inst :: Forall (F'Eq f g) :- F'Eq f g a)
您可以使用 class:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
class (F (f x) ~ g x) => F'Eq f g x
instance (F (f x) ~ g x) => F'Eq f g x
bar' :: forall f g. (Forall (F'Eq f g)) => forall a b. f a -> f b
bar' = helper
where
helper :: forall a b. f a -> f b
helper = case (inst :: Forall (F'Eq f g) :- F'Eq f g a) of
Sub Dict -> case (inst :: Forall (F'Eq f g) :- F'Eq f g b) of
Sub Dict -> bar
假设我有这样一个函数:
{-# LANGUAGE ScopedTypeVariables #-}
class C a where
foo :: forall f a b. (C (f a), C (f b)) => f a -> f b
foo = _
现在,如果我想将 a
和 b
的范围移动到 foo
类型中类型类约束的右侧(比方说,因为我想使用 foo
实现需要在 a
和 b
中多态的类型类方法),它可以使用 Data.Constraint.Forall
:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds, TypeOperators #-}
import Data.Constraint
import Data.Constraint.Forall
foo' :: forall f. (ForallF C f) => forall a b. f a -> f b
foo' = helper
where
helper :: forall a b. f a -> f b
helper = case (instF :: ForallF C f :- C (f a)) of
Sub Dict -> case (instF :: ForallF C f :- C (f b)) of
Sub Dict -> foo
现在,我的问题是,假设我将函数更改为涉及类型等式的内容:
{-# LANGUAGE TypeFamilies, ScopedTypeVariables #-}
type family F a :: * -> *
bar :: forall f g a b. (F (f a) ~ g a, F (f b) ~ g b) => f a -> f b
bar = _
有没有办法使上述技术适应这种情况?
这是我尝试过的:
{-# LANGUAGE TypeFamilies, ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds, TypeOperators #-}
import Data.Constraint
import Data.Constraint.Forall
type F'Eq f g x = F (f x) ~ g x
bar' :: forall f g. (Forall (F'Eq f g)) => forall a b. f a -> f b
bar' = helper
where
helper :: forall a b. f a -> f b
helper = case (inst :: Forall (F'Eq f g) :- F'Eq f g a) of
Sub Dict -> case (inst :: Forall (F'Eq f g) :- F'Eq f g b) of
Sub Dict -> bar
但是(不出所料)这失败了,因为不饱和类型同义词:
Type synonym
‘F'Eq’
should have 3 arguments, but has been given 2In an expression type signature:
Forall (F'Eq f g) :- F'Eq f g a
In the expression:
(inst :: Forall (F'Eq f g) :- F'Eq f g a)
您可以使用 class:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
class (F (f x) ~ g x) => F'Eq f g x
instance (F (f x) ~ g x) => F'Eq f g x
bar' :: forall f g. (Forall (F'Eq f g)) => forall a b. f a -> f b
bar' = helper
where
helper :: forall a b. f a -> f b
helper = case (inst :: Forall (F'Eq f g) :- F'Eq f g a) of
Sub Dict -> case (inst :: Forall (F'Eq f g) :- F'Eq f g b) of
Sub Dict -> bar