使用TypeFamilies无法匹配表达式

时间:2017-07-13 00:59:04

标签: haskell type-families

我试图了解扩展程序TypeFamilies是如何工作的,但是当类型系统无法推断出正确的类型时,我感到很沮丧,例如我认为简单:< / p>

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.Text
import Data.String

class AClass t where
  type family AType t :: *
  somefunction :: t -> AType t

instance AClass Text where
  type AType Text = Int
  somefunction = const 4

instance AClass Int where
  type AType Int = Integer
  somefunction = const 3

所以,我要求将AClass的每个实例与AType的实例相关联(或者我认为我要求Haskell强制执行的实例)

将代码加载到GHCi中时,一切似乎都没问题:

$ ghci -X{OverloadedStrings,GADTs} test.hs
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main>

somefunction的类型是我在代码中声明的内容,对函数的一些调用得到了我的预期:

*Main> :t somefunction
somefunction :: AClass t => t -> AType t
*Main> :t somefunction :: Text -> Int
somefunction :: Text -> Int :: Text -> Int
*Main> (somefunction :: Text -> Int) ""
4
*Main> :t somefunction (""::Text)
somefunction (""::Text) :: Int
*Main> somefunction (""::Text)
4

但是当我试图对somefunction ""(IsString t, AClass t) => AType t)出现的类型定义进行类型定义时,我从类型检查器中得到一个丑陋的错误,即使我只是复制我得到的类型来自typechecker!

*Main> :t somefunction ""
somefunction "" :: (IsString t, AClass t) => AType t
*Main> :t somefunction "" :: (IsString t, AClass t) => AType t

<interactive>:1:20: error:
    • Couldn't match expected type ‘AType t’
                  with actual type ‘AType t0’
      NB: ‘AType’ is a type function, and may not be injective
      The type variable ‘t0’ is ambiguous
    • In the ambiguity check for an expression type signature
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In an expression type signature: (IsString t, AClass t) => AType t
      In the expression:
          somefunction "" :: (IsString t, AClass t) => AType t

无论我做什么,我都不能(或者不知道)如何强制使用类型检查器可以验证并且满意的类型:

*Main> :t somefunction "" :: (t ~ Text, IsString t, AClass t) => AType t

<interactive>:1:1: error:
    • Couldn't match type ‘AType t0’ with ‘Int’
      Expected type: AType t
        Actual type: AType t0
      The type variable ‘t0’ is ambiguous
    • In the expression:
          somefunction "" :: (t ~ Text, IsString t, AClass t) => AType t
*Main> :t somefunction "" :: (t ~ Text, IsString t, AClass t, AType t ~ Int) => AType t

<interactive>:1:1: error:
    • Couldn't match type ‘AType t0’ with ‘Int’
      Expected type: AType t
        Actual type: AType t0
      The type variable ‘t0’ is ambiguous
    • In the expression:
          somefunction "" ::
            (t ~ Text, IsString t, AClass t, AType t ~ Int) => AType t
*Main> somefunction ""

<interactive>:10:1: error:
    • Couldn't match expected type ‘AType t’
                  with actual type ‘AType t0’
      NB: ‘AType’ is a type function, and may not be injective
      The type variable ‘t0’ is ambiguous
    • In the ambiguity check for the inferred type for ‘it’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the inferred type
        it :: forall t. (IsString t, AClass t) => AType t

所以,我的问题是,为什么类型检查器失败了? (它与haskell的一个类型检查器的完整性相关的东西有什么关系吗?)我怎么能修复它,怎么能强制像:: Int:: (t ~ Int, AClass t, AType t ~ Integer) => AType t这样的类型来进行类型检查?

1 个答案:

答案 0 :(得分:1)

假设我们添加了

instance AClass String where
  type AType String = Int
  somefunction = const 10

那么somefunction "" :: Int会评估什么?

可以说""String,因此const 10 "" => 10。 但也可能是""Text,因此const 4 "" => 4

所以,我们的代码含糊不清,GHC正确拒绝它。模糊性从AType String ~ AType Text ~ Int开始:因此,由于它有多个解决方案,所以不可能像AType t ~ Int那样求解类型方程。

GHC在其错误中抱怨此注入问题:

NB: ‘AType’ is a type function, and may not be injective

可以通过向GHC提供预期的t来解决这个问题。最简单的方法是使用注释

somefunction (""::String)
somefunction (""::Text)

更复杂的方法是允许模糊类型,如GHC所建议,然后启用TypeApplications。我们现在可以写

somefunction @ String ""
somefunction @ Text ""

(但似乎更复杂)。