【问题标题】:How do I create a Storable instance for a recursive type?如何为递归类型创建 Storable 实例?
【发布时间】: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

它编译得很好,但我不知道如何实现peekpoke 函数。我认为以与this answer 相同的方式实现这些功能,但此实现仅在列表中的所有元素具有相同大小的情况下才有效,此处并非如此。

对于元素具有浮动大小的递归类型,实现 peekpoke 函数的正确方法是什么?

【问题讨论】:

  • 也许你应该首先定义你期望使用的 C 类型作为你的 Haskell MyType a 的对应物。你的sizeOf 对我来说似乎有点乐观。您的 C 类型可能需要一个 int/enum/whatever 标签来帮助您区分三个 Haskell 构造函数;该标签的大小应添加到所有大小。
  • 值得注意的是,由于历史原因,sizeOf 有错误的签名。它实际上应该是Tagged a Int(或proxy a -> Int)而不是a -> Int。这将清楚地表明这实际上不能依赖于单个值,但对于给定类型的 all 值应该是相同的。 (不过,The documentation 确实这么说。)
  • @leftaroundabout 甚至该签名现在也已成为历史。对于TypeApplicationsAllowAmbigousTypes,它应该真的sizeOf :: Storable a => Int,可以通过sizeOf @a 使用。
  • @HTNW 好吧,是的,但那是最近的一种“历史”。而且它不能与旧的 GHC 向后兼容,更不用说其他 Haskell 实现了,所以对于这样一个低级功能来说,这还不是很实用。

标签: c haskell binding ffi storable


【解决方案1】:

您不能为此设置Storable。这些数据类型需要有一个固定的大小,就像 C structs 一样。另外,请注意 sizeof 不应该检查你给它的值。它只是类型参数的代理/载体,因此您可以编写例如sizeof (undefined::Int)。不妨看看Foreign.Marshal.Array

【讨论】:

    猜你喜欢
    • 2022-01-21
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2013-09-26
    • 1970-01-01
    相关资源
    最近更新 更多