如何使用适用于异构集合中每种类型的约束?
How to use constraints that apply to each type in a heterogenous collection?
我正在尝试找出异构集合,但有一些类型检查问题我无法解决。
data HTypeMap (f :: * -> *) (types :: [*]) where
HNil :: HTypeMap f '[]
HCons :: f e -> HTypeMap f types -> HTypeMap f (e ': types)
(它基本上应该是在某个函子 f
下从类型到该类型的值的映射)。例如:
testMap :: HTypeMap Prelude.Maybe '[Prelude.Int, Prelude.String]
testMap = HCons (Prelude.Just 3) (HCons (Prelude.Just "Hello") HNil)
我一直在尝试制定一个函数,允许我 运行 和 map
以防万一我知道我的集合中的所有类型都受到限制,可以像这样使用:
showEverything :: AllConstrained Show types => HTypeMap f types -> [String]
showEverything = mapConstrained show
type family AllConstrained (c :: u -> Constraint) (ts :: [u]) :: Constraint where
AllConstrained c '[] = ()
AllConstrained c (t ': ts) = (c t, AllConstrained c ts)
我目前的尝试:
- 只是一个简单的函数...GHC 不会让我写这个类型:
mapConstrained :: AllConstrained c types => (forall t. c t => f t -> a) -> HTypeMap f types -> [a]
mapConstrained = _
它说:
• Could not deduce: AllConstrained c0 types
from the context: AllConstrained c types
我完全不明白...我只有一个限制条件需要考虑,它是 c
。 (我有 ScopedTypeVariables
。)
相同样式的类型类也是如此...这里有一些我没有注意到的歧义...
2.
这个笨重的工具确实有效:
data ContraintRunnerF f c r = ContraintRunnerF {runMeF :: forall x. c x => f x -> r}
class MapConstrained c types where
mapConstrained :: forall a f r. AllConstrained c types => ContraintRunnerF f c r -> HTypeMap f types -> [r]
instance MapConstrained c '[] where
mapConstrained _ HNil = []
instance MapConstrained c types => MapConstrained c (t ': types) where
mapConstrained g (HCons e rest) = (runMeF g e) : mapConstrained @c g rest
像这样使用:
showRunnerF :: ContraintRunnerF Prelude.Identity Prelude.Show Prelude.String
showRunnerF = ContraintRunnerF Prelude.show
showRunnerFM :: ContraintRunnerF Prelude.Maybe Prelude.Show Prelude.String
showRunnerFM = ContraintRunnerF Prelude.show
testMap :: HTypeMap Prelude.Maybe '[Prelude.Int, Prelude.String]
testMap = HCons (Prelude.Just 3) (HCons (Prelude.Just "Hello") HNil)
test1 :: [Prelude.String]
test1 = mapConstrained showRunnerFM testMap
但不幸的是,即使是简单的替换也不会进行类型检查,基本上需要我指定所有类型:
test2 :: [Prelude.String]
test2 = mapConstrained (ContraintRunnerF Prelude.show) testMap
• Could not deduce: (c0 Prelude.Int, c0 [Prelude.Char])
arising from a use of ‘mapConstrained’
所以,问题:
- 我如何理解 GHC 在这些方法中存在的问题?
- 我该如何制作满足我需求的功能?
类型变量 c
在 mapConstrained
的类型中被称为 ambiguous 因为从来没有任何方法可以确定该类型变量应该来自什么这是争论。
这个问题的解决方案是TypeApplications
,它允许您为不明确的类型变量显式指定类型。
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, PolyKinds #-}
import Data.Kind
data HTypeMap (f :: * -> *) (types :: [*]) where
HNil :: HTypeMap f '[]
HCons :: f e -> HTypeMap f types -> HTypeMap f (e ': types)
type family AllConstrained (c :: u -> Constraint) (ts :: [u]) :: Constraint where
AllConstrained c '[] = ()
AllConstrained c (t ': ts) = (c t, AllConstrained c ts)
mapConstrained :: AllConstrained c types => (forall t. c t => f t -> a) -> HTypeMap f types -> [a]
mapConstrained _ _ = undefined
testMap :: HTypeMap Prelude.Maybe '[Prelude.Int, Prelude.String]
testMap = HCons (Prelude.Just 3) (HCons (Prelude.Just "Hello") HNil)
-- Note here that `@Show' is the type application - it applies `mapConstrained' at the type level
test = mapConstrained @Show show testMap
在第二种情况下,您必须再次明确指定类型变量:
test2 :: [Prelude.String]
test2 = mapConstrained (ContraintRunnerF @_ @Show Prelude.show) testMap
我正在尝试找出异构集合,但有一些类型检查问题我无法解决。
data HTypeMap (f :: * -> *) (types :: [*]) where
HNil :: HTypeMap f '[]
HCons :: f e -> HTypeMap f types -> HTypeMap f (e ': types)
(它基本上应该是在某个函子 f
下从类型到该类型的值的映射)。例如:
testMap :: HTypeMap Prelude.Maybe '[Prelude.Int, Prelude.String]
testMap = HCons (Prelude.Just 3) (HCons (Prelude.Just "Hello") HNil)
我一直在尝试制定一个函数,允许我 运行 和 map
以防万一我知道我的集合中的所有类型都受到限制,可以像这样使用:
showEverything :: AllConstrained Show types => HTypeMap f types -> [String]
showEverything = mapConstrained show
type family AllConstrained (c :: u -> Constraint) (ts :: [u]) :: Constraint where
AllConstrained c '[] = ()
AllConstrained c (t ': ts) = (c t, AllConstrained c ts)
我目前的尝试:
- 只是一个简单的函数...GHC 不会让我写这个类型:
mapConstrained :: AllConstrained c types => (forall t. c t => f t -> a) -> HTypeMap f types -> [a]
mapConstrained = _
它说:
• Could not deduce: AllConstrained c0 types
from the context: AllConstrained c types
我完全不明白...我只有一个限制条件需要考虑,它是 c
。 (我有 ScopedTypeVariables
。)
相同样式的类型类也是如此...这里有一些我没有注意到的歧义...
2.
这个笨重的工具确实有效:
data ContraintRunnerF f c r = ContraintRunnerF {runMeF :: forall x. c x => f x -> r}
class MapConstrained c types where
mapConstrained :: forall a f r. AllConstrained c types => ContraintRunnerF f c r -> HTypeMap f types -> [r]
instance MapConstrained c '[] where
mapConstrained _ HNil = []
instance MapConstrained c types => MapConstrained c (t ': types) where
mapConstrained g (HCons e rest) = (runMeF g e) : mapConstrained @c g rest
像这样使用:
showRunnerF :: ContraintRunnerF Prelude.Identity Prelude.Show Prelude.String
showRunnerF = ContraintRunnerF Prelude.show
showRunnerFM :: ContraintRunnerF Prelude.Maybe Prelude.Show Prelude.String
showRunnerFM = ContraintRunnerF Prelude.show
testMap :: HTypeMap Prelude.Maybe '[Prelude.Int, Prelude.String]
testMap = HCons (Prelude.Just 3) (HCons (Prelude.Just "Hello") HNil)
test1 :: [Prelude.String]
test1 = mapConstrained showRunnerFM testMap
但不幸的是,即使是简单的替换也不会进行类型检查,基本上需要我指定所有类型:
test2 :: [Prelude.String]
test2 = mapConstrained (ContraintRunnerF Prelude.show) testMap
• Could not deduce: (c0 Prelude.Int, c0 [Prelude.Char])
arising from a use of ‘mapConstrained’
所以,问题:
- 我如何理解 GHC 在这些方法中存在的问题?
- 我该如何制作满足我需求的功能?
类型变量 c
在 mapConstrained
的类型中被称为 ambiguous 因为从来没有任何方法可以确定该类型变量应该来自什么这是争论。
这个问题的解决方案是TypeApplications
,它允许您为不明确的类型变量显式指定类型。
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, PolyKinds #-}
import Data.Kind
data HTypeMap (f :: * -> *) (types :: [*]) where
HNil :: HTypeMap f '[]
HCons :: f e -> HTypeMap f types -> HTypeMap f (e ': types)
type family AllConstrained (c :: u -> Constraint) (ts :: [u]) :: Constraint where
AllConstrained c '[] = ()
AllConstrained c (t ': ts) = (c t, AllConstrained c ts)
mapConstrained :: AllConstrained c types => (forall t. c t => f t -> a) -> HTypeMap f types -> [a]
mapConstrained _ _ = undefined
testMap :: HTypeMap Prelude.Maybe '[Prelude.Int, Prelude.String]
testMap = HCons (Prelude.Just 3) (HCons (Prelude.Just "Hello") HNil)
-- Note here that `@Show' is the type application - it applies `mapConstrained' at the type level
test = mapConstrained @Show show testMap
在第二种情况下,您必须再次明确指定类型变量:
test2 :: [Prelude.String]
test2 = mapConstrained (ContraintRunnerF @_ @Show Prelude.show) testMap