假设我有以下两个面向对象语言的类:
class List:
def reverse() -> None:
...
class Car:
def reverse() -> None:
...
现在,如果我有
list
的实例 List
和 car
的实例 Car
,那么当我编写 reverse
或 list.reverse()
时,我调用哪个
car.reverse()
方法绝对没有歧义。这非常好!
在 Haskell 中,类似的代码类似于:
data List = ...
reverse :: List -> List
reverse = ...
data Car = ...
reverse :: Car -> Car
reverse = ...
有一个迫在眉睫的问题:
reverse
被定义了两次。这个问题并不那么难解决。我们可以定义两个独立的模块List
和Car
,这样两个不同的reverse
函数就位于不同的命名空间中。然后,如果我有一个类型为 list
的变量 List
和一个类型为 car
的变量 Car
,我可以通过编写 reverse
或 List.reverse list
来调用相应的 Car.reverse car
函数。这与上一个示例中的代码 list.reverse()
和 car.reverse()
类似。
最明显的问题是,输入
List.reverse list
而不是 list.reverse()
会更烦人(特别是如果我们用更长的名称替换 List
类型)。 Haskell 中有一些标准方法来处理这个问题吗?请注意,类型类不是这里的解决方案;这两个 reverse
函数具有完全不同的目标。
标准的轻量级惯用法是按照您描述的方式使用模块系统。例如,您会经常看到以下内容:
import qualified Data.Vector as V
import qualified Data.Map as M
foo = (V.fromList bar, M.fromList baz)
曾经有一个有点争议的语言扩展提案,称为“类型定向名称解析”,它就位于这个空间中。争议较少(但仍然有些争议)的是现有的“记录字段消歧”语言扩展,但顾名思义,它仅适用于记录字段。 (另请参阅重复记录字段。)
最后,还有类型类机制,我认为你太容易忽略它了。例如,使用 gi-gtk
#foo bar baz
可能会根据 bar
的类型消除歧义为其中之一:
boxFoo bar baz
alertDialogFoo bar baz