This post提出了!!
案例的问题。接受的答案告诉我们,您实际在做的是创建一个新函数!!
,然后您应该避免导入标准函数。
但是,如果将新功能应用于不同类型而不是标准功能,为什么要这样做呢?编译器是否能够根据其参数选择正确的编译器? 是否有任何编译器标志允许这个?
例如,如果没有为*
[Float] * Float
编译器为何哭泣
> Ambiguous occurrence * > It could refer to either `Main.*', defined at Vec.hs:4:1 > or `Prelude.*',
代码:
(*) :: [Float] -> Float -> [Float]
(*) as k = map (\a -> a*k) as -- here: clearly Float*Float
r = [1.0, 2.0, 3.0] :: [Float]
s = r * 2.0 -- here: clearly [Float] * Float
main = do
print r
print s
答案 0 :(得分:6)
允许编译器根据类型选择正确的函数实现是类型类的目的。没有它们是不可能的。
为了证明这种方法的合理性,您可以阅读介绍它们的论文:How to make ad-hoc polymorphism less ad hoc [PDF]。
答案 1 :(得分:2)
真的,原因是:在Haskell中,并不一定有明确的关联“变量x
具有类型T
”。
Haskell几乎和动态语言一样灵活,因为任何类型都可以是类型变量,即可以具有多态类型。但是在动态语言(以及例如OO多态或C ++模板)中,这种类型变量的类型基本上只是附加到代码中的值变量的额外信息(因此重载的运算符可以看到:参数是{{ 1}} - >执行此操作,是Int
- >执行此操作),在Haskell中,类型变量位于类型语言中完全独立的范围内。这为您提供了许多优势,例如,如果没有这样的系统,更高级别的多态性几乎是不可能的。但是,这也意味着很难推断应该如何解决过载的功能。如果Haskell允许你只是编写重载并假设编译器在解决模糊性方面做了最好的猜测,那么你经常会在意想不到的地方发现奇怪的错误消息。 (实际上,即使你有 no Hindley-Milner类型系统,这也很容易发生重载.C ++因此而臭名昭着。)
相反,Haskell选择强制重载是明确的。您必须首先定义类型类,然后才能重载方法,尽管这不能完全排除混淆编译错误,但这使它们更容易避免。此外,它还允许您使用传统重载无法表达的类型解析表达多态方法,特别是多态结果(非常适合编写非常容易重用的代码)。
答案 2 :(得分:1)
这是一个设计决策,而不是理论上的问题,不在Haskell中包含它。正如您所说,许多其他语言使用类型以特殊方式消除术语之间的歧义。但是类型类具有类似的功能,并且还允许对重载的事物进行抽象。类型导向的名称解析不会。
尽管如此,Haskell已经讨论了类型导向的名称解析形式(例如在解析记录字段选择器的上下文中),并且受到类似于Haskell的一些语言的支持,例如Agda(用于数据构造函数)或Idris(更多)通常)。