首先,根本不可能为同一函数的不同方程赋予不同的类型签名。任何函数只能有一种类型,无论它有多少方程。
其次,负约束在 Haskell 中没有(不会)有任何合理的意义。回想一下类约束的含义:
f :: Num a => a -> a -> a
f x y = x + y
Num a
在类型中f
意味着我们可以将任何类型的类方法应用于Num
类型的值a
。我们有意识地不命名具体类型以获得通用行为。本质上,我们是在说“我们不关心a
究竟是什么,但我们确实知道Num
操作适用于它”。因此,我们可以在and上使用Num
方法,但仅此而已,也就是说,除了 and 上的方法,我们不能使用任何东西。这就是类型类约束是什么以及为什么需要它们。他们正在为函数指定通用接口。x
y
Num
x
y
现在考虑您的假想not Num a
约束。这个声明带来了什么信息?好吧,我们知道a
不应该Num
。但是,这些信息对我们来说完全没有用。考虑:
f :: not Num a => a -> a
f = ???
你可以放置什么来代替???
?显然,我们知道我们不能放置什么。但除了这个签名没有更多的信息
f :: a -> a
唯一的操作f
可能是id
(嗯,undefined
也是可能的,但那是另一回事)。
最后考虑你的例子:
showSquare :: (Show a, not Num a) => a -> String
showSquare x = "I don't know how to square " ++ (show x)
我不是故意给出您示例的第一部分,请参阅我的回答中的第一句话。你不能有不同类型的不同方程。但仅此功能是完全没用的。您可以在这里安全地删除not Num a
约束,它不会改变任何东西。
在静态类型的 Haskell 中,这种负约束的唯一用途是在您提供例如 -constrainted 变量时产生编译时Int
错误not Num a
。但我认为这没有用。