我可以通过功能依赖来实现类型相等吗?

时间:2016-01-07 01:10:01

标签: haskell typeclass

我试图理解MultiParamTypeClassesFunctionalDependencies,以下内容让我感到很明显:

{-# LANGUAGE MultiParamTypeClasses
           , FunctionalDependencies
           , TypeOperators #-}

import Data.Type.Equality

class C a b | a -> b

fob :: (C a b, C a b') => proxy a -> b :~: b'
fob _ = Refl

不幸的是,这不起作用; GHC没有从该背景中得出b ~ b'。有没有办法使这项工作,或功能依赖不是“内部”可用?

2 个答案:

答案 0 :(得分:4)

我不认为这个事实(如fob的类型所述)实际上是正确的。由于类型类的开放世界属性,您可以违反带有模块边界的fundep。

以下示例显示。此代码仅使用GHC 7.10.3进行了测试(旧版本中的fundeps被大量破解 - 不知道接下来会发生什么)。假设您确实可以实现以下内容:

module A 
  (module A
  ,module Data.Type.Equality
  ,module Data.Proxy
  )where 

import Data.Type.Equality
import Data.Proxy 

class C a b | a -> b 

inj_C :: (C a b, C a b') => Proxy a -> b :~: b' 
inj_C = error "oops"

然后再增加几个模块:

module C where 
import A

instance C () Int 

testC :: C () b => Int :~: b 
testC = inj_C (Proxy :: Proxy ()) 

module B where 
import A

instance C () Bool 

testB :: C () b => b :~: Bool 
testB = inj_C (Proxy :: Proxy ()) 

module D where 

import A 
import B
import C 

oops :: Int :~: Bool
oops = testB

oops_again :: Int :~: Bool 
oops_again = testC 

Int :~: Bool显然不正确,因此矛盾,inj_C不可能存在。

如果您不从定义它的模块中导出类inj_C,我相信您仍然可以安全地使用unsafeCoerceC。我已经使用过这种技术,并且已经进行了广泛的尝试,并且无法写出矛盾。不是说这是不可能的,但至少是非常困难和罕见的边缘情况。

答案 1 :(得分:3)

您不需要求助于多个模块来欺骗功能依赖性检查程序。以下是仍然使用HEAD构建的错误fundeps的两个示例。它们改编自GHC测试套件。

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies,
             FlexibleInstances, FlexibleContexts,
             UndecidableInstances, DataKinds, PolyKinds,
             GADTs #-}

module M where


data K x a = K x

class Het a b | a -> b where
  het :: m (f c) -> a -> m b
instance Het t t where het = undefined

class GHet (a :: * -> *) (b :: * -> *) | a -> b
instance            GHet (K a) (K [a])
instance Het a b => GHet (K a) (K b)


data HBool = HFalse | HTrue

class TypeEq x y b | x y -> b
instance {-# OVERLAPS #-} (HTrue ~ b)  => TypeEq x x b
instance {-# OVERLAPS #-} (HFalse ~ b) => TypeEq x y b

fundep检查器仍然比以前好多了!

相关问题