首先,根本不可能为同一函数的不同方程赋予不同的类型签名。任何函数只能有一种类型,无论它有多少方程。
其次,负约束在 Haskell 中没有(不会)有任何合理的意义。回想一下类约束的含义:
f :: Num a => a -> a -> a
f x y = x + y
Num a在类型中f意味着我们可以将任何类型的类方法应用于Num类型的值a。我们有意识地不命名具体类型以获得通用行为。本质上,我们是在说“我们不关心a究竟是什么,但我们确实知道Num操作适用于它”。因此,我们可以在and上使用Num方法,但仅此而已,也就是说,除了 and 上的方法,我们不能使用任何东西。这就是类型类约束是什么以及为什么需要它们。他们正在为函数指定通用接口。xyNumxy
现在考虑您的假想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。但我认为这没有用。