我想把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)
以下是一些更重要的事实 -
即使我使用ExistentialQuantification或RankNTypes并在数据定义中直接声明(Storable type1,Storable type2)(构造函数外部或字段本身),也会出现相同的错误.
如果我将sizeOf定义更改为,我可以使其工作
sizeOf(FullData xy)= sizeOf x + sizeOf y
但这只有在我有FullData的具体实例时才有效,而我的一些程序需要在创建实例之前知道数据的大小(我知道,我可能只有一个虚拟实例,但这看起来有点难看).
发生此错误是因为:: typeN
定义中的注释sizeOf
不引用实例声明中的同名类型.这就是Haskell的工作原理 - 类型变量仅限于它们出现的类型签名.
调用的扩展ScopedTypeVariables
名将改变它.除其他外,它使实例声明范围中使用的类型变量超过声明中的所有定义.
只需在文件开头插入以下行:
{-# LANGUAGE ScopedTypeVariables #-}
或者,你可以做一些比模式匹配更懒的东西.由于FullData
是记录,访问者功能适当地限制类型.
sizeOf fd = sizeOf (first fd) + sizeOf (second fd)
只要sizeOf
对嵌套类型正确实现,那就是非严格的.由于嵌套调用sizeOf
不会评估它们的参数,因此调用first
和second
实际上不会对它们进行求值 - 但是它们的类型将被计算,并迫使事情正常工作.
您甚至可以使用无可辩驳的模式匹配来执行相同的操作而不使用字段访问器:
sizeOf ~(FullData x y) = sizeOf x + sizeOf y
该~
断言编译器,该模式将总是一致的,它可以推迟实际测试,直到值x
或y
需要.如果你骗了编译器有关的图案总是匹配,就会产生一个运行时错误时,x
或y
使用,因为它试图看看他们,但发现该模式实际上并没有正确匹配.这与前一种情况类似 - 如果不使用x和y,一切都很好.