gpt4 book ai didi

haskell - 为涉及向量的递归数据结构定义可存储

转载 作者:行者123 更新时间:2023-12-04 06:03:56 27 4
gpt4 key购买 nike

我有以下形式的数据结构(V 是 Data.Storable.Vector):

data Elems = I {-# UNPACK #-} !GHC.Int.Int32
| S {-# UNPACK #-} !GHC.Int.Int32 {-# UNPACK #-} !(Ptr CChar)
| T {-# UNPACK #-} !(V.Vector Elems)
deriving (Show)

我首先为非递归形式编写了一个自定义的可存储定义(即,没有 T 构造函数)。然后,我尝试为 T 添加自定义 peek 和 poke 定义使用 ForeignPtrlength来自 Vector 的信息(代码如下)。 GHC 编译器提示 Storable没有为 ForeignPtr Elems 定义实例类型。我的问题是是否可以在 Storable 定义中将 ptr 存储到 Vector,而不必为 ForeignPtr 编写 Storable 实例定义。

来自 Haddocs文档中,ForeignPtr 似乎只是一个分配有终结器的 Ptr:

The essential difference between ForeignPtrs and vanilla memory references of type Ptr a is that the former may be associated with finalizers.



我不想通过使用 Ptr 来解决此问题而不是 ForeignPtr ,因为最终确定它的问题。所以,我更喜欢存储 ForeignPtr 的位置(通过 Ptr (ForeignPtr a) ),以便 GHC 垃圾收集器知道对它的引用。但是,这种方法会迫使我定义一个 Storable instance (因为约束 (Storable a) => Ptr a 这是有道理的)。

有没有办法在 Storable 中将 ptr 存储和检索到 Vector 中,而无需为 ForeignPtr 定义 Storable 实例?如果没有,那么编写 ForeignPtr 的 Storable 定义是必须的。在那种情况下,它会是什么样子?我的猜测是它只会将 Ptr 存储到 ForeignPtr。

完整代码如下:
{-# LANGUAGE MagicHash #-}
import qualified Data.Vector.Storable as V
import Foreign
import Foreign.C.Types (CChar)
import Foreign.Marshal.Array (lengthArray0)
import GHC.Int

data Elems = I {-# UNPACK #-} !GHC.Int.Int32
| S {-# UNPACK #-} !GHC.Int.Int32 {-# UNPACK #-} !(Ptr CChar)
| T {-# UNPACK #-} !(V.Vector Elems)
deriving (Show)

instance Storable Elems where
sizeOf _ = sizeOf (undefined :: Word8) + sizeOf (undefined :: Int32) + sizeOf (undefined :: Ptr CChar)
alignment _ = 4

{-# INLINE peek #-}
peek p = do
let p1 = (castPtr p::Ptr Word8) `plusPtr` 1 -- get pointer to start of the element. First byte is type of element
t <- peek (castPtr p::Ptr Word8)
case t of
1 -> do
x <- peek (castPtr p1 :: Ptr GHC.Int.Int32)
return (I x)
2 -> do
x <- peek (castPtr p1 :: Ptr GHC.Int.Int32)
y <- peek (castPtr (p1 `plusPtr` 4) :: Ptr (Ptr CChar)) -- increment pointer by 4 bytes first
return (S x y)
_ -> do
x <- peek (castPtr p1 :: Ptr Int)
y <- peek (castPtr (p1 `plusPtr` 8) :: Ptr (ForeignPtr Elems))
return (T (V.unsafeFromForeignPtr y 0 x)) -- return vector

{-# INLINE poke #-}
poke p x = case x of
I a -> do
poke (castPtr p :: Ptr Word8) 1
poke (castPtr p1) a
S a b -> do
poke (castPtr p :: Ptr Word8) 2
poke (castPtr p1) a
poke (castPtr (p1 `plusPtr` 4)) b -- increment pointer by 4 bytes first
T x -> do
poke (castPtr p :: Ptr Word8) 3
let (fp,_,n) = V.unsafeToForeignPtr x
poke (castPtr p1) n
poke (castPtr (p1 `plusPtr` 8)) fp

where p1 = (castPtr p :: Ptr Word8) `plusPtr` 1 -- get pointer to start of the element. First byte is type of element

最佳答案

ForeignPtr无法制作 Storable ,因为它们的实现需要一种将一个或多个终结器指针关联到原始指针的方法,并且这种关联是依赖于运行时的。制作 ForeignPtr可存储,需要存储关联的Ptr (这很容易)和关联的终结器数组(这是不可能的,因为终结器是运行时内部的,并且可能绑定(bind)到 GHC 运行时的 GC)。

不过,这不是这里需要解决的问题。

问题是没有合理的方法来制作包含 Vector 的东西。进入某事Storable .一个 Vector需求托管 内存其内容(Storable.Vector 的定义是 data Vector a = Vector Int (ForeignPtr a) 加上一些严格的注释),但 Storable 的全部目的是将一些值存储到 非托管 内存。此外,Vector使用 不同金额内存取决于它的长度,但 Storable数据结构必须使用 常数 内存量。

您需要重新考虑您的数据结构试图建模的内容。你真的需要存储一个Vector像这样?请记住,您存储的是 VectorElems ,这意味着你可以有一个值 T包含 Vector包含 T包含 Vector包含 T , ETC。

我认为您可能正在尝试对以下数据结构进行建模,但我可能错了:

data Elems = OneElem Elem | ManyElems (Vector Elem)

data Elem
= I !GHC.Int.Int32
| S !GHC.Int.Int32 !(Ptr CChar)

如果您确实需要您描述的递归数据结构,请尝试实现它:
data Elems
= I !GHC.Int.Int32
| S !GHC.Int.Int32 !(Ptr CChar)
| T !GHC.Int.Int32 !(Ptr Elems)

指向某些 Elems 的指针使用 常数 内存,并且可以指向 非托管 内存,因此您可以为其创建可存储的实例。

关于haskell - 为涉及向量的递归数据结构定义可存储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8595029/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com