考虑面向对象的语言:
大多数人都有面向对象编程背景,熟悉各种语言中常见且直观的界面,这些界面捕获了 Java 的精髓 Collection
& List
接口(interface)。 集合
是指不一定具有自然排序/索引的对象集合。 List
是一个具有自然排序/索引的集合。这些接口(interface)抽象了 Java 中的许多库数据结构,其他语言中的等效接口(interface)也是如此,并且需要对这些接口(interface)有深入的了解才能有效地处理大多数库数据结构。
过渡到 Haskell:
Haskell 有一个类型类系统,它作用于类型,类似于对象上的接口(interface)。 Haskell 似乎有一个 well designed type-class hierarchy当类型考虑功能时,涉及 Functor、Applicative、Monad 等。他们显然想要correct and well-abstracted type-classes 。然而,当你查看许多 Haskell 的容器( List
、 Map
、 Sequence
、 Set
、 Vector
)时,它们几乎都具有非常相似(或相同)的功能,但不是通过类型类抽象的.
一些示例:
null
用于测试“空”长度
/元素计数的大小
elem
/member
用于集合包含空
和/或singleton
用于默认构造union
用于集合并集(\\)
/diff
用于设置差异(!)
/(!!)
用于不安全索引(部分函数)(!?)
/查找
以进行安全索引(总功能)
如果我想使用上述任何函数,但我导入了两个或更多容器,我必须开始隐藏导入模块中的函数,或者仅从模块中显式导入必要的函数,或者限定导入的模块。但由于所有函数都提供相同的逻辑功能,因此看起来很麻烦。如果函数是从类型类定义的,而不是在每个模块中单独定义的,则编译器的类型推断机制可以解决此问题。只要底层容器共享类型类,它也会使切换底层容器变得简单(即:让我们只使用 Sequence
而不是 List
以获得更好的随机访问效率)。
为什么 Haskell 没有一个 Collection
和/或 Indexable
类型类来统一并概括其中一些功能?
最佳答案
正如其他答案所指出的,Haskell 倾向于使用不同的词汇。但是,我认为他们没有很好地解释差异的原因。
在像 Java 这样的语言中,函数不是“一等公民”;而是“一等公民”。确实,最新版本中提供了匿名函数,但这种风格的界面(Collection、Indexable、Interable 等)是在此之前设计的。
这使得传递我们的代码变得乏味,因此我们更喜欢将其他人的数据传递给我们的代码。例如:
- 实现 Java 的
Iterable
的数据让我们编写for (Foo x : anIterable) { ... }
- 实现 PHP
ArrayAccess
的数据让我们可以编写anArrayAccess[anIndex]
这种风格也可以在实现生成器的面向对象语言中看到,因为这是我们在 aGenerator 中编写 for yieldedElement: ...
的另一种方式。
Haskell 对类型类采取了不同的方法:我们更喜欢将我们的代码传递给其他人的数据。一些(简化的)示例:
仿函数
接受我们的代码并将其应用到它们“包含”的任何元素Monad
接受我们的代码并以某种“序列”应用它Foldable
接受我们的代码并使用它来“减少”其内容
Java 只需要 Iterable
,因为我们必须在我们的 for
循环中调用我们的代码,因此我们可以确保它被正确调用。 Haskell 需要更具体的类型类,因为其他人的代码将调用我们的代码,因此我们需要指定如何调用它;它是 map
、折叠
、展开
等吗?
值得庆幸的是,类型系统帮助我们选择正确的方法;)
关于haskell - 为什么 Haskell 缺少 "obvious"类型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25191659/