How do I create a Storable instance for a recursive type?
我在Haskell模块中具有以下数据类型,我想编写一个可存储实例,以通过FFI将其与C一起使用:
1 2 3 4
| data MyType a =
TypeDouble Double
| TypeLst [a]
| TypeAdd (MyType a) (MyType a) |
我首先定义了sizeOf函数:
1 2 3 4
| 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函数。我认为实现这些功能的方式与此答案相同,但是只有当列表中的所有元素都具有相同的大小(而不是这里的大小)时,此实现才起作用。
对于元素具有浮动大小的递归类型,实现peek和poke函数的正确方法是什么?
- 也许您应该首先定义希望与Haskell MyType a对应的C类型。您的sizeOf似乎对我有点乐观。您的C类型可能需要int / enum / whatever标签,以帮助您区分三个Haskell构造函数。该标签的尺寸应添加到所有尺寸中。
-
值得注意的是,出于历史原因,sizeOf具有错误的签名。它实际上应该是Tagged a Int(或proxy a -> Int)而不是a -> Int。可以清楚地知道,它实际上并不依赖于单个值,但是对于给定类型的所有值都应该相同。 (不过文档确实说了这一点。)
-
@leftaroundabout甚至那个签名现在都是历史性的。对于TypeApplications和AllowAmbigousTypes,它实际上应该是sizeOf :: Storable a => Int,可以通过sizeOf @a使用。
-
@HTNW好吧,是的,但这是最近的一种"历史性"。而且它不能与旧的GHC向后兼容,更不用说其他Haskell实现了,因此对于这样的低级功能来说,这还不是很实用。
您不能为此Storable。这些数据类型需要具有固定的大小,就像C struct s一样。另外,请注意,sizeof不应检查您提供的值。它只是type参数的代理/载体,因此您可以编写例如sizeof (undefined::Int)。也许看看Foreign.Marshal.Array