【发布时间】:2019-08-13 22:44:29
【问题描述】:
这似乎适用于 GHCi 和 GHC。我将首先展示一个使用 GHCi 的示例。
给定i 类型已推断如下:
Prelude> i = 1
Prelude> :t i
i :: Num p => p
鉴于succ 是在Enum 上定义的函数:
Prelude> :i Enum
class Enum a where
succ :: a -> a
pred :: a -> a
-- …OMITTED…
并且Num 不是Enum 的“子类”(如果我可以使用该术语):
class Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
-- …OMITTED…
为什么succ i 不返回错误?
Prelude> succ i
2 -- works, no error
我希望:type i 被推断为:
Prelude> i = 1
Prelude> :type i
i :: (Enum p, Num p) => p
(我使用的是“GHC v. 8.6.3”)
补充:
阅读@RobinZigmond 评论和@AlexeyRomanov 回答后,我注意到1 可以解释为多种类型之一和多种类之一。
感谢@AlexeyRomanov 的回答,我对用于决定歧义表达式使用哪种类型的默认规则有了更多的了解。
但是,我认为 Alexey 的回答并不能完全解决我的问题。我的问题是关于i 的类型。这与succ i 的类型无关。
这是关于succ 参数类型(Enum a)和i 的表观类型(Num a)之间的不匹配。
我现在开始意识到我的问题必须源于一个错误的假设:“一旦i 被推断为i :: Num a => a,那么i 就可以没有别的” .因此,我很困惑地看到 succ i 的评估没有错误。
除了明确声明的内容之外,GHC 似乎还在推断 Enum a。
x :: Num a => a
x = 1
y = succ x -- works
但是,当类型变量作为函数出现时,它不会添加Enum a:
my_succ :: Num a => a -> a
my_succ z = succ z -- fails compilation
在我看来,附加到函数的类型约束似乎比应用于变量的类型约束更严格。
GHC 说my_succ :: forall a. Num a => a -> a 并给出
forall a 没有出现在 i 和 x 的类型签名中,我认为这意味着 GHC 不会再为 my_succ 类型推断任何类。
但这似乎又是错误的:我已经用以下(我第一次输入 RankNTypes)检查了这个想法,显然 GHC 仍然推断Enum a:
{-# LANGUAGE RankNTypes #-}
x :: forall a. Num a => a
x = 1
y = succ x
看来函数的推理规则比变量的推理规则更严格?
【问题讨论】:
-
您已将
i定义为1,它可以是任何类型的Num类的成员。当您使用succ时,这进一步将类型限制为Enum类。但这不是问题,因为这两个类中都有多种类型,2代表每个类中的结果。 -
@RobinZigmond 确实如此(对于标准类型;您可以定义自己的不同工作方式),但这根本不是 GHCi 给出
2作为答案的原因。 -
您可能还喜欢:Why can a Num act like a Fractional?。事实上,我很想将此标记为重复。简而言之,
i的用户可以选择它想要的Num的哪个实例,特别是用户可以选择一个也有Enum实例的类型。 -
@DanielWagner 这很有趣!它们似乎确实相关,但我不确定我们是否可以称它们为重复:我仍在消化到目前为止所说的内容。
标签: haskell types typeclass ghci