由其各部分组成一个Storable

时间:2013-12-03 06:32:24

标签: haskell

我想把Foreign.Storable分成两部分......

import Foreign

data FullData type1 type2 = FullData {first::type1, second::type2}

instance (Storable type1, Storable type2)=>Storable (FullData type1 type2) where
    sizeOf _ = sizeOf (undefined::type1) + sizeOf (undefined::type2)
    alignment _ = 0 --I am just setting this to zero for testing....

main = putStrLn $ show $ sizeOf (undefined::FullData Int Char)

然而,这失败了 -

storableTest.hs:13:44:
Could not deduce (Storable a1) arising from a use of `sizeOf'
from the context (Storable type1, Storable type2)
  bound by the instance declaration at storableTest.hs:12:10-74
The type variable `a1' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance (Storable type1, Storable type2) =>
           Storable (FullData type1 type2)
    -- Defined at storableTest.hs:12:10
  instance Storable Bool -- Defined in `Foreign.Storable'
  instance Storable Char -- Defined in `Foreign.Storable'
  ...plus 16 others
In the second argument of `(+)', namely
  `sizeOf (undefined :: type2)'
In the expression:
  sizeOf (undefined :: type1) + sizeOf (undefined :: type2)
In an equation for `sizeOf':
    sizeOf _
      = sizeOf (undefined :: type1) + sizeOf (undefined :: type2)

以下是一些更重要的事实 -

  1. 即使我使用ExistentialQuantification或RankNTypes并在数据定义中直接声明(Storable type1,Storable type2)(构造函数外部或字段本身),也会出现相同的错误。

  2. 如果我将sizeOf定义更改为

    ,我可以使用它

    sizeOf(FullData x y)= sizeOf x + sizeOf y

  3. 但这只有在我有FullData的具体实例时才有效,我的一些程序需要在创建实例之前知道数据的大小(我知道,我可能只有一个虚拟实例,但这似乎有点难看)。

1 个答案:

答案 0 :(得分:6)

发生此错误是因为:: typeN定义中的sizeOf注释未引用实例声明中的同名类型。这就是Haskell的工作原理 - 类型变量仅限于它们出现的类型签名。

名为ScopedTypeVariables的扩展名会改变这一点。除其他外,它使实例声明范围中使用的类型变量超过声明中的所有定义。

只需在文件开头插入以下行:

{-# LANGUAGE ScopedTypeVariables #-}

或者,您实际上可以做一些比模式匹配更懒的事情。由于FullData是记录,因此访问者函数会适当地限制类型。

sizeOf fd = sizeOf (first fd) + sizeOf (second fd)

只要为嵌套类型正确实现sizeOf,这就是非严格的。由于对sizeOf的嵌套调用不会评估它们的参数,因此实际上不会对firstsecond的调用进行求值 - 但会计算它们的类型,并强制执行某些操作正常。

您甚至可以使用无可辩驳的模式匹配来执行相同的操作而不使用字段访问器:

sizeOf ~(FullData x y) = sizeOf x + sizeOf y

~向编译器声明模式将始终匹配,并且它可以推迟实际测试它,直到需要xy的值。如果你向编译器说谎该模式始终匹配,那么在使用xy时会产生运行时错误,因为它会尝试查找它们但发现模式实际上并不匹配正常。这与前一种情况类似 - 如果不使用x和y,一切都很好。