我想将Haskell类型的Convertible实例写入其C表示
看起来像这样:
instance Convertible Variable (IO (Ptr ())) where
现在GHC抱怨道:
Illegal instance declaration for `Convertible
Variable (IO (Ptr ()))'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Convertible Variable (IO (Ptr ()))'
如果你的实例声明中有自由类型,我认为需要灵活实例,但事实并非如此。我可以在添加正确的pragma时进行编译,但任何人都可以解释为什么我需要它吗?
答案 0 :(得分:13)
是的,您需要灵活的实例。没有它,你的所有类型类实例都必须看起来像
instance Foo (Maybe a) where
instance Foo (IO a) where
instance Foo (Either a b) where
如果你想做除TypeConstructor a1 a2 a3 ...
以外的任何事情(并且a
必须是类型变量),那么你需要灵活的实例。但它是最常见的语言扩展之一,不要冒汗使用它。
答案 1 :(得分:2)
在这种情况下,您经常可以避免FlexibleInstances
。有两种通用方法:
instance ConvIO a => Convertible Variable (IO a) where
method = methodIO
class ConvIO p where
methodIO :: ...
-- similar to the signature for the Convertible method,
-- but with Variable and IO baked in
instance ConvIOPtr u => ConvIO (Ptr u) where
methodIO = methodIOPtr
class ConvIOPtr u where
methodIOPtr :: ...
instance ConvIOPtr () where ...
当您需要多个以相同构造函数为首的实例时,此方法很有效。
开启GADTs
或TypeFamilies
并写入
instance a ~ Ptr () => Convertible Variable (IO a) where ...
这种方法对类型推断有很大帮助,但只有在需要一个以IO
为首的实例时才有意义。
您可以使用辅助类来浏览IO
,然后使用等式约束来浏览Ptr
。
instance u ~ () => ConvIO (Ptr u) where ...
或者您可以使用等式约束来通过IO
和辅助类来完成Ptr
:
instance (a ~ Ptr u, ConvIOPtr u) => Convertible Variable (IO a)
如果你需要一个实例,其中一个参数是一个类型变量,那么你根本就不能避免FlexibleInstances
。您可以使用newtype解决问题,但这不值得。