使用关联类型族时推断类型类约束

时间:2016-06-27 02:27:14

标签: haskell types typeclass type-families

我知道you can add constraints on associated type families and data families。这样做是对您班级的所有实例强制执行约束。

但我无法弄清楚如何在实例派生或函数声明中推断出这些约束。例如,此代码无法键入check:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}

import Data.Proxy ( Proxy )

class Eq (FooT a) => Foo a where
    type FooT a :: *

-- Can't infer it in an instance derivation
data CantInferEq a = CantInferEq (FooT a) deriving Eq

-- Also can't infer it in a function declaration.
-- The Proxy is there to avoid non-injectivity issues.
cantInferEq :: Proxy a -> FooT a -> FooT a -> Bool
cantInferEq _ x y = x == y

错误消息是:

Test.hs:11:52: No instance for (Eq (FooT a)) …
      arising from the first field of ‘CantInferEq’ (type ‘FooT a’)
    Possible fix:
      use a standalone 'deriving instance' declaration,
        so you can specify the instance context yourself
    When deriving the instance for (Eq (CantInferEq a))

Test.hs:16:23: No instance for (Eq (FooT a)) arising from a use of ‘==’ …
    In the expression: x == y
    In an equation for ‘cantInferEq’: cantInferEq _ x y = x == y

Compilation failed.

这里发生了什么?是否有解决方法来实现我想要的行为?

1 个答案:

答案 0 :(得分:5)

问题的症结在于只给出一个FooT a,你无处可以从中提取Eq实例字典。

解决方法是在类型类要求中明确,从而有一个传递Eq dict的地方:

{-# LANGUAGE StandaloneDeriving, UndecidableInstances #-}

data CantInferEq a = CantInferEq (FooT a)    
deriving instance (Eq (FooT a)) => Eq (CantInferEq a)

cantInferEq :: (Eq (FooT a)) => Proxy a -> FooT a -> FooT a -> Bool
cantInferEq _ x y = x == y

或者您可以通过将UndecidableInstances字典与Eq (FooT a)构造函数打包来避免使用CantInferEq

{-# LANGUAGE GADTs, StandaloneDeriving #-}
data CantInferEq a where
    CantInferEq :: (Eq (FooT a)) => FooT a -> CantInferEq a
deriving instance Eq (CantInferEq a)