不是由GADT匹配和功能依赖推断的类型

  • 本文关键字:依赖 类型 功能 GADT haskell
  • 更新时间 :
  • 英文 :


我对Haskell类型系统有一个误解,我认为这可能是常见的,但是我找不到一个解释,对于这个简单的例子所显示的特定类型检查失败:

{-#LANGUAGE GADTs, FunctionalDependencies #-}
module GaF where
class XDeterminesY x y | x -> y
instance XDeterminesY Int Double
data Wrapper x where
WrappedInt :: Wrapper Int
func :: XDeterminesY x y => Wrapper x -> y -> Double
func WrappedInt a = a

GHC抱怨不能从上下文x ~ Int中推断出y ~ Double。我认为执行这样的演绎是声明函数依赖的全部意义。

我认为执行这样的演绎是声明函数依赖的全部意义。

不幸的是,情况并非如此。在GADT的模式匹配过程中,fundep从不细化刚性类型变量。直觉上,它们在某些情况下应该这样做,但是它们没有这样做。我猜这是因为它们早在gts出现之前就出现在Haskell中了,所以没有先例。

这很烦人,我同意。这就是为什么我认为类型族通常是一个更好的主意。在我看来,如果可能的话,应该用类型族代替FunDeps(注意,在class C a b c | a->c, b->c中我们确实不能这样做)。

顺便注意,在注入类型族扩展中可以观察到类似的失败:人们会期望GHC从F a ~ F b推断出a ~ b,但它没有。

无论如何,我想你现在想知道"如果这不是基金的重点,他们的重点是什么?"嗯,考虑:

class C a b | a -> b where
foo :: a -> b -> String
bar :: a -> String
instance C Bool Int where ...

如果没有FunDeps,像bar True这样的调用将是模棱两可的:在一个实例中我们可以使用C Bool Int来解析约束,但可能存在另一个实例。这里的问题是类型bar :: a -> String不涉及b,因此无法知道我们是否可以安全地提交到实例。该类型被认为是二义性的。

对于FunDeps,我们承诺不会有其他实例,所以只涉及a的类型不再是模糊的,并且实例解析可以很好地工作。

(顺便说一下,现在这种歧义可以用类型应用程序在调用站点手动解决,但过去不是这样的。)

最新更新