3

可以Storable通过 GHC 的通用派生机制进行派生:http: //hackage.haskell.org/package/derive-storable(以及https://hackage.haskell.org/package/derive-storable-plugin以获得性能)。但是,我可以找到的唯一用于派生的库Data.Vector.Unbox使用模板 Haskell:http ://hackage.haskell.org/package/vector-th-unbox 。它还需要用户编写一些代码;它不是完全自动的。

我的问题是,类似的库是否deriving-storable也存在,或者由于某些基本方式与 不同,Unbox这是不可能的?如果是后者,这是否意味着也无法创建一个允许自动派生任何类型的库,因为我找不到这样的库。UnboxStorableUnboxStorable

我问是因为理想情况下我想避免使用模板 Haskell 和使用vector-th-unbox.

4

1 回答 1

3

假设我们有一些Generic_类可以在我们自己的类型和一些恰好有一个Unbox实例的统一表示之间进行转换(这相当于变体MVectorVector实例Unboxed):

class Generic_ a where
  type Rep_ (a :: Type) :: Type
  to_ :: a -> Rep_ a
  from_ :: Rep_ a -> a

然后我们可以使用它来获得MVector/方法的通用实现Vector

-- (auxiliary definitions of CMV and uncoercemv at the end of this block)
-- vector imports (see gist at the end for a compilable sample)
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as UM
import Data.Vector.Generic.Mutable.Base (MVector(..))



-- MVector

gbasicLength :: forall a s. CMV s a => UM.MVector s a -> Int
gbasicLength = basicLength @UM.MVector @(Rep_ a) @s . coerce

gbasicUnsafeSlice :: forall a s. CMV s a => Int -> Int -> UM.MVector s a -> UM.MVector s a
gbasicUnsafeSlice i j = uncoercemv . basicUnsafeSlice @UM.MVector @(Rep_ a) @s i j . coerce

-- etc.


-- idem Vector


-- This constraints holds when the UM.MVector data instance of a is
-- representationally equivalent to the data instance of its generic
-- representation (Rep_ a).
type CMV s a = (Coercible (UM.MVector s a) (UM.MVector s (Rep_ a)), MVector UM.MVector (Rep_ a))

-- Sadly coerce doesn't seem to want to solve this correctly so we use
-- unsafeCoerce as a workaround.
uncoercemv :: CMV s a => UM.MVector s (Rep_ a) -> UM.MVector s a
uncoercemv = unsafeCoerce

现在,如果我们有一些泛型类型

data MyType = MyCons Int Bool ()

我们可以定义一个与元组同构的通用实例

instance Generic_ MyType where
  type Rep_ MyType = (Int, Bool, ())
  to_ (MyCons a b c) = (a, b, c)
  from_ (a, b, c) = MyCons a b c

从那里开始,有一个完全通用的方法来获取它的Unbox实例,如果你有YourType它自己的Generic_实例,你可以把它拿来替换MyTypeYourType.

newtype instance UM.MVector s MyType
  = MVMyType { unMVMyType :: UM.MVector s (Rep_ MyType) }

instance MVector UM.MVector MyType where
  basicLength = gbasicLength
  basicUnsafeSlice = gbasicUnsafeSlice
  -- etc.

-- idem (Vector U.Vector MyType)

-- MVector U.Vector & Vector UM.MVector   =   Unbox
instance Unbox MyType

理论上,所有这些样板文件都可以通过内部语言特性自动化(与 TemplateHaskell 或 CPP 不同)。但是,在当前的情况下,存在各种问题。

首先,Generic_本质上Generic来自GHC.Generics。然而,由 GHC 派生的统一表示不是元组,而是缺乏实例(,)的特定类型构造函数(:+::*:M1等) 。Unbox

  • 这样Unbox的实例可以添加Generic直接使用
  • generics-eot有一个Generic依赖元组的变体,可以直接替代这里Generic_

第二,MVectorVector相当多的方法。为了避免必须将它们全部列出,人们可能希望利用DerivingVia(或GeneralizedNewtypeDeriving),但是它们不适用,因为有一些多态一元方法可以防止强制转换(例如,basicUnsafeNew)。目前,我能想到的最简单的抽象方法是 CPP 宏。事实上,vector 包在内部使用了该技术,并且它可能以某种方式可重用。我相信正确解决这些问题需要对 Vector/MVector 架构进行深入的重新设计。

要点(不完整,但可编译):https ://gist.github.com/Lysxia/c7bdcbba548ee019bf6b3f1e388bd660

于 2019-06-27T15:05:10.510 回答