我试图了解扩展程序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
这样的类型来进行类型检查?
答案 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 ""
(但似乎更复杂)。