【发布时间】:2017-10-17 21:07:34
【问题描述】:
我在 Haskell 模块中有以下数据类型,我想编写一个可存储实例以通过 FFI 将其与 C 一起使用:
data MyType a =
TypeDouble Double
| TypeLst [a]
| TypeAdd (MyType a) (MyType a)
我首先定义了sizeOf 函数:
instance Storable a => Storable (MyType a) where
sizeOf (TypeDouble _) = sizeOf (0 :: Double)
sizeOf (TypeLst lst) = sum $ map sizeOf lst
sizeOf (TypeAdd a b) = sizeOf a + sizeOf b
它编译得很好,但我不知道如何实现peek 和poke 函数。我认为以与this answer 相同的方式实现这些功能,但此实现仅在列表中的所有元素具有相同大小的情况下才有效,此处并非如此。
对于元素具有浮动大小的递归类型,实现 peek 和 poke 函数的正确方法是什么?
【问题讨论】:
-
也许你应该首先定义你期望使用的 C 类型作为你的 Haskell
MyType a的对应物。你的sizeOf对我来说似乎有点乐观。您的 C 类型可能需要一个 int/enum/whatever 标签来帮助您区分三个 Haskell 构造函数;该标签的大小应添加到所有大小。 -
值得注意的是,由于历史原因,
sizeOf有错误的签名。它实际上应该是Tagged a Int(或proxy a -> Int)而不是a -> Int。这将清楚地表明这实际上不能依赖于单个值,但对于给定类型的 all 值应该是相同的。 (不过,The documentation 确实这么说。) -
@leftaroundabout 甚至该签名现在也已成为历史。对于
TypeApplications和AllowAmbigousTypes,它应该真的是sizeOf :: Storable a => Int,可以通过sizeOf @a使用。 -
@HTNW 好吧,是的,但那是最近的一种“历史”。而且它不能与旧的 GHC 向后兼容,更不用说其他 Haskell 实现了,所以对于这样一个低级功能来说,这还不是很实用。
标签: c haskell binding ffi storable