简体   繁体   English

如何为通用向量创建ListIsomorphic实例?

[英]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

Instances for other types 其他类型的实例

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. 使用toListfromList任何地方也需要一个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]

Here Be Dragons 这里是龙

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: 以下是我提出的两个解决方案:

  1. Change the class parameters: 更改类参数:

     class ListIsomorphic la where toList :: la -> [a] fromList :: [a] -> la instance (V.Vector va) => Listable va where ... 
  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM