需要灵活的实例?

Ing*_*das 7 haskell typeclass

我想将Haskell类型的Convertible实例写入其C表示

它看起来像这样:

instance Convertible Variable (IO (Ptr ())) where
Run Code Online (Sandbox Code Playgroud)

现在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 ()))'
Run Code Online (Sandbox Code Playgroud)

如果你的实例声明中有自由类型,我认为需要灵活实例,但事实并非如此.我可以在添加正确的pragma时进行编译,但有人可以解释为什么我需要这个吗?

Dan*_*zer 14

是的,你需要灵活的实例.没有它,你的所有类型类实例都必须看起来像

instance Foo (Maybe a) where
instance Foo (IO a)    where
instance Foo (Either a b) where
Run Code Online (Sandbox Code Playgroud)

如果你想做除TypeConstructor a1 a2 a3 ...(并且a必须是类型变量)以外的任何事情,那么你需要灵活的实例.但它是最常见的语言扩展之一,不要冒汗使用它.


dfe*_*uer 5

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 ...
Run Code Online (Sandbox Code Playgroud)

当您需要由同一构造函数领导的多个实例时,此方法非常有效。

使用等式约束

打开GADTsTypeFamilies并写入

instance a ~ Ptr () => Convertible Variable (IO a) where ...
Run Code Online (Sandbox Code Playgroud)

这种方法往往对类型推断有很大帮助,但只有当您只需要一个以 开头的实例时才有意义IO

你可以混合搭配

您可以使用辅助类来遍历IO,然后使用等式约束来遍历Ptr

instance u ~ () => ConvIO (Ptr u) where ...
Run Code Online (Sandbox Code Playgroud)

或者您可以使用等式约束来遍历IO并使用辅助类来遍历Ptr

instance (a ~ Ptr u, ConvIOPtr u) => Convertible Variable (IO a)
Run Code Online (Sandbox Code Playgroud)

这些不起作用的地方

如果您需要一个其参数之一是类型变量的实例,那么您确实根本无法避免FlexibleInstances。您也许可以使用新类型来解决该问题,但不值得这么麻烦。