相关类型的家庭抱怨`pred :: T a - > Bool`用" NB:'T'是一个类型函数,可能不是单射的"

时间:2018-05-03 12:23:53

标签: haskell types type-families

此代码:

{-# LANGUAGE TypeFamilies #-}

module Study where

class C a where
    type T a :: *
    pred :: T a -> Bool

- 给出了这个错误:

.../Study.hs:7:5: error:
    • Couldn't match type ‘T a’ with ‘T a0’
      Expected type: T a -> Bool
        Actual type: T a0 -> Bool
      NB: ‘T’ is a type function, and may not be injective
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for ‘Study.pred’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the class method:
        Study.pred :: forall a. A a => T a -> Bool
      In the class declaration for ‘A’
  |
7 |     pred :: T a -> Bool
  |     ^^^^^^^^^^^^^^^^^^^

type个关键字替换为data次修复。

  • 为什么一个错了,另一个错了?
  • 他们的意思是什么?"可能不是单射的"?如果甚至不允许一对一的那种功能是什么?这与pred
  • 的类型有何关系?

1 个答案:

答案 0 :(得分:6)

instance C Int where
  type T Int = ()
  pred () = False

instance C Char where
  type T Char = ()
  pred () = True

所以现在你有两个pred的定义。因为类型族只分配类型同义词,所以这两个定义具有签名

pred :: () -> Bool

pred :: () -> Bool
嗯,看起来很相似,不是吗?类型检查器无法区分它们。那么,

是什么
pred ()

应该是? TrueFalse

要解决此问题,您需要一些明确的方法来提供某些用例中特定pred应属于哪个实例的信息。正如您自己发现的那样,一种方法是更改​​为关联的data系列:data T Int = TIntdata T Char = TChar将是两种可区分的新类型,而不是同义词类型,无法确保它们实际上是不同的。即数据族总是单射的;类型家庭有时候不是。在没有其他提示的情况下,编译器假定 no 类型族是单射的。

您可以使用其他语言扩展名声明一个类型系列:

{-# LANGUAGE TypeFamilyDependencies #-}
class C a where
  type T a = (r :: *) | r -> a
  pred :: T a -> a

=只是将r的{​​{1}} esult绑定到一个名称,因此它在injectivity注释T的范围内,其内容类似于函数依赖: r -> a的{​​{1}} esult足以确定r个参数。以上情况现在是非法的; Ta一起违反了注入性。只有一个本身是可以接受的。

或者,您可以按照编译器的提示进行操作; type T Int = ()使原始代码编译。但是,您需要type T Char = ()来解析使用站点上的实例:

-XAllowAmbiguousTypes