如何为通用向量创建ListIsomorphic实例? [英] How do I create a ListIsomorphic instance for generic vectors?

查看:128
本文介绍了如何为通用向量创建ListIsomorphic实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下类:

  class ListIsomorphic l其中
toList :: l a - > [a]
fromList :: [a] - > la

如何使用 Data.Vector为矢量类型编写实例。通用?这是行不通的:

  instance(V.Vector v a)=> ListIsomorphic v其中
toList = V.toList
fromList = V.fromList

给我:

  test.hs:31:10:
变量'a'的出现次数多于实例头部
在约束中:V.Vector va
(使用UndecidableInstances来允许)
在'ListIsomorphic v'


解决方案

不要。为所有 v 添加一个实例到 Listable 类将因使用重叠实例而变得麻烦。



A Vector va => v 不是同构于列表,因为它受限于哪些项目可以是列表的元素。你需要一个捕获这个约束的类,像

  { - #LANGUAGE Con​​straintKinds# - } 
{ - #LANGUAGE TypeFamilies# - }

import Data.Constraint

class ConstrainedList l其中
类型Elem la :: Constraint
toList :: Elem la => l a - > [a]
fromList :: Elem l a => [a] - > la

不用为所有人添加 ConstrainedList 实例类型 Vector va => v 这将使我们进入重叠的实例领域,相反,我们将仅为我们感兴趣的类型定义它。以下将覆盖所有类型,其中 Vector 实例在向量包中。

 导入限定的Data.Vector.Primitive作为VP 
将限定的Data.Vector.Generic导入为VG

实例ConstrainedList VP.Vector其中
类型Elem VP.Vector a = VG.Vector VP.Vector a
toList = VG.toList
fromList = VG。 fromList



其他类型的实例



您可以为常规列表 [] 写一个 ConstrainedList 实例,它只需要空元素的约束。

 实例ConstrainedList []其中
类型Elem [] a =()
toList = id
fromList = ID

使用 toList fromList 还需要 Elem la 实例。

  cmap ::(ConstrainedList l,Elem 1a,Elem lb)=> (a  - > b) - > l a  - > l b 
cmap f = fromList。地图f。 toList

当我们知道列表和元素的具体类型时,这些函数很容易使用,有限制。

  cmap(+1)[1,2,3,4] 



这里是龙



不要尝试下面的内容。如果您对与列表同构的事物感兴趣而没有额外的约束,请为其创建另一个类。这只是说明当你将自己设计成一个角落时你可以做什么:召唤一条龙。



你也可以编写需要证明没有约束的函数在 ConstrainedList 的元素上。这是GHC不真正支持的约束包和编程样式的领域,但没有足够的约束例子,所以我会在这里留下这个。

  { - #LANGUAGE TypeOperators# - } 
{ - #LANGUAGE FlexibleContexts# - }
{ - #LANGUAGE ScopedTypeVariables# - }

map':: forall la b。 (ConstrainedList l,():=> Elem l a,():=> Elem 1 b)=>
(a - > b) - > l a - > l b
map'f = case(ins ::(): - Elem l a)of {Sub Dict - >
case(ins ::(): - Elem b){Sub Dict - >
fromList。地图f。 toList
}}

我们可以检查 ConstrainedList 通过检查 Elem la〜()没有任何约束,但如果约束以不同的方式写入,则不起作用。

  { - #LANGUAGE FlexibleInstances# - } 

类任何
实例任何

data AList a = AList {getList :: [a]}
派生(显示)

实例ConstrainedList AList其中
类型Elem AList a =任何
toList = getList
fromList = AList

即使()隐含<$ c Any a 不是同一类型$ c>任何一个。约束包通过将它们转化为类型类来捕获这样的关系 Class :=>

<$ p $ { - #LANGUAGE MultiParamTypeClasses# - }

- class()=>任何
实例Class()(Any a)其中
cls = Sub字典

- instance()=>任何
实例():=>任何一个地方
ins = Sub Dict

所有这些工作让我们可以轻松地重用函数而无需提供所有这些字典,当一个具体的列表类型已知。

  map''::(a  - > b) - > ; AList a  - > AList b 
map''=地图'


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? 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.

A Vector v a => v isn't isomorphic to a list because it is constrained by which items can be elements of the list. 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 v a => 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.

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.

instance ConstrainedList [] where
    type Elem [] a = ()
    toList   = id
    fromList = id

Anywhere that uses toList or fromList will also require an Elem l a instance.

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. 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.

{-# 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 l a ~ (), but that wouldn't work if its constraint was written in a different way.

{-# 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. The constraints package captures relationships like this by reifying them to the type classes Class and :=>

{-# 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'

这篇关于如何为通用向量创建ListIsomorphic实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆