【发布时间】:2011-01-04 05:43:28
【问题描述】:
考虑函数,
add a b = a + b
这行得通:
*Main> add 1 2
3
但是,如果我添加一个类型签名,指定我想添加相同类型的东西:
add :: a -> a -> a
add a b = a + b
我收到一个错误:
test.hs:3:10:
Could not deduce (Num a) from the context ()
arising from a use of `+' at test.hs:3:10-14
Possible fix:
add (Num a) to the context of the type signature for `add'
In the expression: a + b
In the definition of `add': add a b = a + b
所以 GHC 显然 可以 推断出我需要 Num 类型约束,因为它只是告诉我:
add :: Num a => a -> a -> a
add a b = a + b
工作。
为什么 GHC 要求我添加类型约束?如果我在做泛型编程,为什么它不能只适用于知道如何使用+ 运算符的任何东西?
在 C++ 模板编程中,您可以轻松做到这一点:
#include <string>
#include <cstdio>
using namespace std;
template<typename T>
T add(T a, T b) { return a + b; }
int main()
{
printf("%d, %f, %s\n",
add(1, 2),
add(1.0, 3.4),
add(string("foo"), string("bar")).c_str());
return 0;
}
编译器计算出add 的参数类型,并为该类型生成函数的版本。 Haskell 的方法似乎有根本的不同,你能描述一下,并讨论取舍吗?在我看来,如果 GHC 简单地为我填写类型约束,它就会得到解决,因为它显然决定它是需要的。不过,为什么要使用类型约束呢?只要该函数仅在参数位于Num 中的有效上下文中使用,为什么不直接编译成功?
【问题讨论】:
-
为什么它应该通过添加一个约束当你明确告诉它你不需要约束(通过声明
add :: a -> a -> a)来神奇地将类型签名变成不那么通用的东西?另请注意,在 Haskell 中,没有(+)重载但不是Num的实例(因为(+)在Num中,所以要重载它,您必须声明一个Num实例)。
标签: haskell type-inference typeclass type-systems