非内射型封闭型族

时间:2018-09-28 03:32:16

标签: haskell type-families injective-function

我有这个公认的人为设计的代码

{-# LANGUAGE DataKinds, TypeFamilies #-}

data Foo = Foo

type family Id (n :: Foo) a where
    Id 'Foo a = a

data Bar (n :: Foo) = Bar

class Dispatch (n :: Foo) where
    consume :: Id n a -> Bar n -> a

consume' :: Dispatch n => Id n [Bool] -> Bar n -> [Bool]
consume' = consume

consume'' :: Dispatch n => Id n [Bool] -> Bar n -> Bool
consume'' g x = and (consume' g x)

这可以编译并正常工作。但是,如果我将最终的consume''定义替换为

consume'' :: Dispatch n => Id n [Bool] -> Bar n -> Bool
consume'' g x = and (consume g x)

(请注意consume而不是consume'),然后出现错误消息

noinject.hs:17:30: error:
    • Couldn't match expected type ‘Id n (t0 Bool)’
                  with actual type ‘Id n [Bool]’
      NB: ‘Id’ is a non-injective type family
      The type variable ‘t0’ is ambiguous
    • In the first argument of ‘consume’, namely ‘g’
      In the first argument of ‘and’, namely ‘(consume g x)’
      In the expression: and (consume g x)
    • Relevant bindings include
        x :: Bar n (bound at noinject.hs:17:13)
        g :: Id n [Bool] (bound at noinject.hs:17:11)
        consume'' :: Id n [Bool] -> Bar n -> Bool
          (bound at noinject.hs:17:1)
   |
17 | consume'' g x = and (consume g x)
   |                              ^
Failed, no modules loaded.

如果我们假设Id是非内射的,则会发生错误,因为对于某些consume并非{{ 1}}。我很了解我的问题是:为什么consume :: Id n (t0 Bool) -> Bar n -> t0 Bool 不是实际上是内射的。它有两个参数:第一个参数只有一个有效值,而t0在第二个参数中显然是单射的,那么GHC为什么认为这是一个非单射的族?

1 个答案:

答案 0 :(得分:3)

Injective type families是类型家族之上的一个单独扩展,您需要特殊的语法将一个类型家族声明为一个。内推性不会被推断。