[英]How do I create a ListIsomorphic instance for generic vectors?
Given the following class: 鉴于以下课程:
class ListIsomorphic l where
toList :: l a -> [a]
fromList :: [a] -> l a
How can I write a instance for vector types using Data.Vector.Generic
? 如何使用
Data.Vector.Generic
为矢量类型编写实例? This doesn't work: 这不起作用:
instance (V.Vector v a) => ListIsomorphic v where
toList = V.toList
fromList = V.fromList
Giving me: 给我:
test.hs:31:10:
Variable ‘a’ occurs more often than in the instance head
in the constraint: V.Vector v a
(Use UndecidableInstances to permit this)
In the instance declaration for ‘ListIsomorphic v’
Don't . 不要 。 Adding an instance for all
v
to your Listable
class will become cumbersome to use due to overlapping instances. 由于重叠实例,将所有
v
的实例添加到Listable
类将变得很麻烦。
A Vector va => v
isn't isomorphic to a list because it is constrained by which items can be elements of the list. Vector va => v
与列表不同构,因为它受哪些项可以是列表元素的约束。 You'd need a class that captures this constraint, something like 你需要一个捕获这种约束的类,比如
{-# 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
Instead of adding ConstrainedList
instances for all types Vector va => v
which would get us into overlapping instances territory, instead we'll define it only for the types we're interested in. The following will cover all the types with a Vector
instance in the vector package. 而不是为所有类型添加
ConstrainedList
实例Vector va => 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
You can write a ConstrainedList
instance for regular lists []
that requires only the empty constraint for its elements. 您可以为常规列表
[]
编写ConstrainedList
实例,该实例仅需要其元素的空约束。
instance ConstrainedList [] where
type Elem [] a = ()
toList = id
fromList = id
Anywhere that uses toList
or fromList
will also require an Elem la
instance. 使用
toList
或fromList
任何地方也需要一个Elem la
实例。
cmap :: (ConstrainedList l, Elem l a, Elem l b) => (a -> b) -> l a -> l b
cmap f = fromList . map f . toList
When we know concrete types for the lists and elements these functions will be easy to use without messing around with constraints. 当我们知道列表和元素的具体类型时,这些函数将易于使用而不会弄乱约束。
cmap (+1) [1,2,3,4]
Don't try what follows. 不要尝试以下内容。 If you are interested in the class of things that are isomorphic to lists without additional constraints, just make another class for it.
如果您对没有附加约束的列表同构的事物类感兴趣,那么只需为它创建另一个类。 This just demonstrates what you can do when you've designed yourself into a corner: summon a dragon.
这只是展示了当你把自己设计成一个角落时你能做什么:召唤一条龙。
You can also write functions that require a proof that there is no constraint on the elements of a ConstrainedList
. 您还可以编写需要证明
ConstrainedList
元素没有约束的函数。 This is way off into the realms of the constraints
package and programming styles that aren't really supported by GHC, but there aren't enough constraints
examples so I'll leave this one here. 这是GHC并不真正支持的
constraints
包和编程样式的领域,但是没有足够的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
}}
We could check that a ConstrainedList
has no constraint by just checking that Elem la ~ ()
, but that wouldn't work if its constraint was written in a different way. 我们可以通过检查
Elem la ~ ()
来检查ConstrainedList
是否没有约束,但是如果它的约束以不同的方式写入,那么它将不起作用。
{-# 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
()
isn't the same type as Any a
even though ()
implies Any a
. ()
与Any a
类型不同,即使()
暗示Any a
。 The constraints package captures relationships like this by reifying them to the type classes Class
and :=>
约束包通过将它们引用到类类
Class
和:=>
来捕获这样的关系
{-# LANGUAGE MultiParamTypeClasses #-}
-- class () => Any a
instance Class () (Any a) where
cls = Sub Dict
-- instance () => Any a
instance () :=> Any a where
ins = Sub Dict
All of that work lets us easily reuse functions without providing all those dictionaries when a concrete list type is known. 所有这些工作都可以让我们轻松地重用函数,而无需在知道具体列表类型时提供所有这些字典。
map'' :: (a -> b) -> AList a -> AList b
map'' = map'
I frequently run into this problem. 我经常遇到这个问题。 Here are two solutions I've come up with:
以下是我提出的两个解决方案:
Change the class parameters: 更改类参数:
class ListIsomorphic la where toList :: la -> [a] fromList :: [a] -> la instance (V.Vector va) => Listable va where ...
Use constraint kinds 使用约束种类
class ListIsomorphic l where type C la :: Constraint toList :: la -> [a] fromList :: [a] -> la instance Listable v where type C va = (V.Vector va) ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.