实例头中重复的tyvar:绑定还是引用?

时间:2019-06-19 12:47:01

标签: haskell typeclass

我实例头的思维模型是它们是类型级别的模式匹配,具有像变量绑定一样的tyvar绑定。使用FlexibleInstances,您可以在实例头中重复使用tyvar。但是您不能在学期一级做到这一点。考虑

class (Eq a, Eq b) => C a b  where
  foo :: a -> b -> String

instance C a a  where              -- repeated `a'
  -- the args are same type so we can compare them
  foo ...   = "equal"              -- see below
  foo _x _y = "not equal"

instance {-# OVERLAPPABLE #-} C a b  where
  foo _  _  = "not comparable"

对于这种"equal"案例,我想写

foo  x   x  = "equal"

但是模式中不允许重复的变量:拒绝的Conflicting definitions for 'x'。这是因为每个变量必须唯一地绑定到foo then 的参数上,我们才能引用它们。而是去

foo  x   y  | x == y = "equal"

那么重复的tyvar业务如何运作呢?在instance C a a中,哪个a是绑定站点,哪个是引用站点?幕后的编译器在执行等同于绑定到不同名称的tyvar的操作,然后应用防护吗?

1 个答案:

答案 0 :(得分:1)

实例选择通常在ghc/compiler/types/InstEnv.hs中进行,它使用“匹配”,这是一种受限制的统一形式,其中带有变量的模板通过替换那些模板变量而与另一种类型统一。

因此,当GHC决定需要C Int Int的实例字典时,它将尝试按以下顺序将C Int Int与模板C a aC a b进行匹配/统一(即,通过应用tcMatchTys中的函数ghc/compiler/types/Unify.hs来确定是否存在变量a和/或b的替代项,从而允许这些模板之一与{ {1}}。

这是C Int Int中的一个实现细节,但是在我看来,tcMatchTys可以通过将C Int Int绑定到基于C a a的模板而与模板a相匹配。在第一个Int上,然后根据第二个a验证a已绑定到Int,因此我猜第一个a是绑定站点,并且第二个a是引用站点,尽管更准确地说它们都是统一/匹配站点。如果更改顺序,语义将不会改变。

重叠实例的处理在此匹配过程之后进行。生成匹配模板的完整列表,然后在a中由insert_overlapping折叠:

lookupInstEnv

函数-- in function `lookupInstEnv`, file `InstEnv.hs` final_matches = foldr insert_overlapping [] all_matches 会在允许重叠的地方严格过滤掉更通用的实例(并处理不连贯的实例)。然后将最终列表与单例列表进行匹配,如果零个或多个模板匹配,则错误。

请注意,上面的匹配过程可能涉及多态替换,所以:

insert_overlapping

使用相同的匹配过程来确定gack :: [t] -> String gack xs = foo xs xs 与替换项C [t] [t]下的模板C a a匹配。 (它在替换项a := [t]下也匹配C a b,但优势匹配获胜。)