我有这种数据类型和实例声明:
class Expr a where
lit :: Integer -> a
data Mod7 = Mod7 Integer deriving (Eq, Show)
instance Expr Mod7 where
lit x = Mod7 (x `mod` 7)
这样编译就可以了。我认为那是因为这一行
lit x = Mod7 (x `mod` 7)
推断x
是可以传递给mod
的类型。没有一些明确的声明怎么会发生这种推断?
mod的定义是
mod :: Integral a => a -> a -> a
因此,根据以上声明,完全有可能lit
被传递了没有声明函数的Integral
类型。 GHC如何知道要分配给x
的类型?
答案 0 :(得分:8)
类型推断与任何其他上下文相同。在这种情况下,有两行推理证明x
是Integer
。
x
出现在表达式Mod7 (x `mod` 7)
中。由于Mod7
构造函数声明为接受Integer
自变量,因此x `mod` 7
必须是Integer
。由于mod
的类型为Integral a => a -> a -> a
,因此如果x `mod` 7
的结果为Integer
,则x
和7
都必须为{{ 1}}(这仅在Integer
成立的情况下有效,但可以这样做)。
Integral Integer
已声明为类型lit
(在Expr a => Integer -> a
的类定义中)。 Expr a
被绑定为x
定义中的参数,因此它的类型必须为lit
。
特定于实例声明的唯一事情是类型检查器可以使用此特定实例的类型实例化在类中声明的函数的类型。因此,它实际上知道(因为在Integer
中,instance Expr Mod7
的定义是针对lit
的。但是,甚至不需要建立lit :: Integer -> Mod7
,因为自变量x :: Integer
的类型在lit
的每个实例中都是相同的(此特定于实例的知识用于确定调用Expr
构造函数是构建返回值的正确方法,但不是与推断Mod7
的类型无关。