不要。由于重叠的实例,v
为你的类添加一个实例将变得很麻烦。Listable
AVector v a => v
不与列表同构,因为它受哪些项目可以是列表元素的限制。您需要一个捕获此约束的类,例如
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Constraint
class ConstrainedList l where
type Elem l a :: Constraint
toList :: Elem l a => l a -> [a]
fromList :: Elem l a => [a] -> l a
ConstrainedList
我们不会为所有类型添加实例,Vector v a => v
这会使我们进入重叠的实例领域,而是只为我们感兴趣的类型定义它。下面将涵盖Vector
向量包中具有实例的所有类型。
import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Generic as VG
instance ConstrainedList VP.Vector where
type Elem VP.Vector a = VG.Vector VP.Vector a
toList = VG.toList
fromList = VG.fromList
其他类型的实例
您可以为其元素只需要空约束的ConstrainedList
常规列表编写一个实例。[]
instance ConstrainedList [] where
type Elem [] a = ()
toList = id
fromList = id
任何使用toList
或fromList
也需要Elem l a
实例的地方。
cmap :: (ConstrainedList l, Elem l a, Elem l b) => (a -> b) -> l a -> l b
cmap f = fromList . map f . toList
当我们知道列表和元素的具体类型时,这些函数将很容易使用,而不会受到约束。
cmap (+1) [1,2,3,4]
这里是龙
不要尝试以下内容。如果您对与没有额外约束的列表同构的事物类感兴趣,只需为它创建另一个类。这只是展示了当你将自己设计到一个角落时你可以做什么:召唤一条龙。
您还可以编写需要证明对 a 的元素没有约束的函数ConstrainedList
。这constraints
与 GHC 不真正支持的包和编程风格领域相去甚远,但是没有足够的constraints
示例,所以我将把这个留在这里。
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
map' :: forall l a b. (ConstrainedList l, () :=> Elem l a, () :=> Elem l b) =>
(a -> b) -> l a -> l b
map' f = case (ins :: () :- Elem l a) of { Sub Dict ->
case (ins :: () :- Elem l b) of { Sub Dict ->
fromList . map f . toList
}}
我们可以ConstrainedList
通过检查 a 来检查 a 是否没有约束Elem l a ~ ()
,但是如果它的约束以不同的方式编写,那将不起作用。
{-# LANGUAGE FlexibleInstances #-}
class Any a
instance Any a
data AList a = AList {getList :: [a]}
deriving (Show)
instance ConstrainedList AList where
type Elem AList a = Any a
toList = getList
fromList = AList
()
与Any a
即使()
隐含的类型不同Any a
。约束包通过将它们具体化为类型类来捕获这样的关系,Class
并:=>
{-# LANGUAGE MultiParamTypeClasses #-}
-- class () => Any a
instance Class () (Any a) where
cls = Sub Dict
-- instance () => Any a
instance () :=> Any a where
ins = Sub Dict
所有这些工作让我们可以轻松地重用函数,而无需在已知具体列表类型时提供所有这些字典。
map'' :: (a -> b) -> AList a -> AList b
map'' = map'