假设我有一个可以取消装箱/重新装箱的值的类:
class Unboxable a (rep :: RuntimeRep) (unboxedTy :: TYPE rep) | a -> rep, a -> unboxedTy where
unbox :: a -> unboxedTy
rebox :: unboxedTy -> a
Run Code Online (Sandbox Code Playgroud)
像这样的例子非常好:
instance Unboxable Int 'IntRep Int# where
unbox (I# w) = w
rebox = I#
Run Code Online (Sandbox Code Playgroud)
但是如果我尝试支持不可装箱值的元组,例如
instance (Unboxable a repa unboxedTyA, Unboxable b repb unboxedTyB)
=> Unboxable (a, b) ('TupleRep '[ repa, repb ]) (# unboxedTyA, unboxedTyB #) where
unbox (a, b) = (# unbox a, unbox b #)
rebox (# a# , b# #) = ( rebox a# , rebox b# )
Run Code Online (Sandbox Code Playgroud)
我得到一个超出我理解的错误:
A levity-polymorphic type is not allowed here:
Type: unboxedTyA
Kind: TYPE repa
In the type of binder ‘a#’
|
32 | rebox (# a# , b# #) = ( rebox a# , rebox b# )
| ^^
Run Code Online (Sandbox Code Playgroud)
unboxifrebox被注释掉会出现类似的错误。如果那很重要,我在 ghc 8.8.2 上。
这到底是什么意思,有没有办法表达最后一个实例?
你不能有一个带有 unknown 的变量RuntimeRep。这种情况根本不可能。例如,for 实例(Float, Float)必须存储/加载 32 位值,但 for 实例(Double, Double)将处理 64 位值。但是,这样的实例必须是这个实例的特化,因此共享代码,使得这种区分变得不可能。为了抓住这一点,当一个变量被引入时,它的类型与 匹配TYPE rep,如果rep不完全知道(本质上,值需要传递的“调用约定”),你看到的错误被提出。短语“levity polymorphism”是一个遗留物,“levity”指的是提升类型之间的差异(通过包含一个底部值来定义并且它们都被装箱(例如Int,[String])) 与未提升的类型(没有底值,其中一些被装箱 ( ByteArray#) 和一些被拆箱 ( Int#)) 如果你真的想,你可以使用 Template Haskell 来生成这些装箱和拆箱函数,但是你无法获得所有这些(因为有无限多个并且您不能使用多态性)。