我已经编写了自己的异构列表实现(我第一次读到异构列表here时,我的实现与他们的非常相似)
{-# LANGUAGE GADTs, DataKinds, TypeOperators #-}
data HList a where
(:>) :: a -> HList b -> HList (a ': b)
Nil :: HList '[]
infixr 6 :>
这很棒;然而,一旦我发现自己使用了这些异构列表,我发现自己经常想要表达这样的想法,即每个类型都属于一个特定的类型类。我天真的第一个解决方案是为每个新类型类完全重写HList
数据类型。这是针对Eq
的(仅举个例子;它不是我唯一关心的类型类):
{-# LANGUAGE GADTs, DataKinds, TypeOperators #-}
data EqHList a where
(:>) :: (Eq a) => a -> EqHList b -> EqHList (a ': b)
Nil :: EqHList '[]
infixr 6 :>
这有一大堆问题。首先,每当我想要一个新的类型类时,我都需要重写它。此外,在我的旧的异构列表上工作的函数不能在新的列表上工作。
我的下一个解决方案是使用空类型类。
{-# LANGUAGE GADTs, DataKinds, TypeOperators, FlexibleInstances, FlexibleContexts #-}
data HList a where
(:>) :: a -> HList b -> HList (a ': b)
Nil :: HList '[]
infixr 6 :>
class Eqed a
instance Eqed (HList '[])
instance (Eq a, Eqed (HList b)) => Eqed (HList (a ': b))
这里,Eqed
的一个实例是一个HList
,它的所有元素都是Eq
的实例。这肯定比上一个解决方案更好,但是我仍然觉得它缺乏。每当我想要谈论不同类型的类时,我仍然需要复制粘贴一堆代码。我觉得这类问题可以通过更多的类型级编程来解决。
有没有更好的方法?
发布于 2018-06-02 04:33:14
您可以通过参数化来泛化Eqed
(需要一些扩展,GHC的错误消息会告诉您):
import Data.Kind (Constraint)
class CMap (c :: * -> Constraint) (xs :: [*])
instance CMap c '[]
instance (c x, CMap c xs) => CMap c (x ': xs)
然而,这并不是很好的表现,因为CMap c (x ': xs)
并不意味着c x
,它只是反过来。一种方法可能是添加一个可以使用这些单独约束的方法,但这似乎很麻烦。另一种是使用类型族:
type family CMap (c :: * -> Constraint) (xs :: [*]) :: Constraint where
CMap c '[] = ()
CMap c (x ': xs) = (c x, CMap c xs)
发布于 2018-06-02 04:33:48
您可以使用ConstraintKinds
将约束设置为HList
的参数
data HList c a where
(:>) :: (c a) => a -> HList c b -> HList c (a ': b)
Nil :: HList c '[]
exampleList :: HList Eq '[Int, String, Double]
exampleList
= (1 :: Int)
:> ("two" :: String)
:> (3.0 :: Double)
:> Nil
或者使用ExistentialTypes
/GADTs
和常规列表,如果您只需要类型类,并且不介意丢失有关列表中哪些具体类型的静态类型信息:
data SomeEq = forall a. Eq a => SomeEq a
data SomeEq where
SomeEq :: Eq a => a -> SomeEq
exampleList :: [SomeEq]
exampleList =
[ SomeEq (1 :: Int)
, SomeEq ("two" :: String)
, SomeEq (3.0 :: Double)
]
但是,对于Eq
,这并不是特别有用,除非您还传播有关类型相等的信息,以便您有一些有用的东西来比较抽象包装值。实际上,您唯一能做的就是将包装的值与其自身进行比较。
根据您的特定应用程序,可能会有更好/更简单的选项。
https://stackoverflow.com/questions/50650543
复制相似问题