为什么在一个数据结构上有100个函数比在10个数据结构上有10个函数更好?

76

我在很多地方看到过这句话:

“比起10个函数作用于10种数据结构,使用100个函数处理同一种数据结构更好。“ ——艾伦·佩利斯

但我从未见过对此进行解释的原因。是不是只是一个想法,即应该尝试从第一个数据结构中推导出其他9个数据结构,以避免重复数据?我感觉自己缺少一些上下文。


2
因为 100 个函数 > 10 个函数。 - Jim Balter
3
因为一个数据结构上的100个函数更通用,因此提供了更好的组合性,而对于10个数据结构上的10个函数,则是因其特定于它们的数据结构而 less (或不可能) 跨数据结构进行组合。 - mljrg
2个回答

104
这段引文来自于1982年出版的Alan Perlis的编程格言
这句话的意思在Lisp中得到了很好的体现,其中有大量的函数专门处理和操作列表,你可以仅使用列表和处理列表的各种函数就可以完成很多工作,这使它们比任何单一目的数据结构更加强大。 Lua是另一个例子,使用表模拟类。为什么要使用表来创建对象而不是像面向对象语言那样创建语言级别的类和对象?因为你的对象现在是一个表,所以你可以在你的对象上使用任意数量的已定义为表的函数,而不需要额外付费!更好的是,我们不必用类特定的语法来混淆语言,并且必须重新定义我们想要用于我们类的表的函数。
Perl所说的绝对是Lisp和函数式编程中的一种显著思考方式。这些100个函数在你的一个数据结构上可以组合在许多独特的方式中,因为它们都在同一个数据结构上运行,但你不能像10个数据结构上的10个函数那样混合地使用它们,因为它们只被定义为在它们特定的数据结构上工作。

更现代、更简单的变化是以抽象方式思考。如果我们在编写Java代码,你会更愿意在List接口上编写100个函数,还是只编写同一组十个函数,分别针对ArrayList、LinkedList等?


1
我认为这个答案的最后一段强调了为什么Alan Perlis的名言不再适用。充其量,它归结于您认为什么构成“数据结构”。 - J D
"[...] 但是你不能真正将这10个函数与10个数据结构混合使用,因为它们只定义为在特定的数据结构上工作。" 部分函数在某种程度上缓解了这个问题。 - TheFooProgrammer
26
@JonHarrop 我不同意它已经不适用了,在Clojure世界中可以看到,我做了很长时间的面向对象编程,现在我深入学习函数式编程,实践中我发现这句话是多么正确,一旦你放弃对象,大部分结构只是普通的映射,你可以重复使用相同的函数并在其上进行组合,与我在面向对象世界中的工作相比,我发现这种方式更加明智。所以,试试Clojure吧,看看你是否仍然认为这句话已经过时 :) - Wilker Lucio
1
这个答案的最后一段展示了2011年是多么遥远。考虑到那时函数式编程的复兴,珀利斯的箴言非常适用。最好在工具箱中拥有一百个经过充分测试的函数,并使用简单的数据结构进行工作。 - John Hardy
1
许多面向对象编程语言都提供了一种在多个不同的自定义类型之间共享行为的方式:接口带默认方法、traits、mixin、组合、继承等。这样做确实增加了更多的复杂性和语法,但是你无需像最后一段所说的那样为每个需要它们的数据类型复制/粘贴相同的10个函数。话虽如此,在面向对象编程语言中如何重用功能则不像只有数据结构和函数时那么明显。 - jmrah

13

《计算机程序的构造与解释》(SICP)对您的问题进行了以下回答:

来自SICP的截图

您可以在这里查看该书的在线版本原始内容。

编辑(包含评论):

“在 Pascal 中,可以声明各种各样的数据结构,这导致函数内部出现了特化。” 特化是不好的,因为它抑制了“意外发现”/创造力 - 用我的话来说。

换句话说,如果函数过于特定,则无法以在创建函数时未知的方式重用它们。

一个很好的例子是foldhttps://hackage.haskell.org/package/base-4.8.1.0/docs/Data-Foldable.html),它是一个与数据结构无关的普通高阶函数。它可以用于树形结构,例如。

data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a).

1
这并没有回答为什么。 - isomorphismes
6
在Pascal中,声明的各种数据结构的丰富多样性会导致函数内部的特殊化。用我的话来说,特殊化是不好的,因为它抑制了“意外收获”(serendipity)。换句话说,如果函数过于特定,那么它们不能以在函数创建时未知的方式被重复使用。一个很好的例子是fold(网址:https://hackage.haskell.org/package/base-4.8.1.0/docs/Data-Foldable.html),它是一种与数据结构无关的通用高阶函数。例如,它可以用于树形结构,如`data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)`。 - jhegedus
@jhegedus,我建议您将您的评论添加到您的答案中。这是一个非常好的补充。 - Sam R.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接