数学的正式语言与编程的口语语言的混合使这些对话变得困难。您在这里处理两个上下文加载的单词:“可组合”和“函数”。
数学中的函数组合
“函数”的数学概念A → B
是从某个集合 A 到某个集合 B 的映射,“函数组合”是由下式表示的特定操作∘
。对于一些f: A → B
and g: B → C
, g∘f
是一个函数A → C
这样(g∘f)(x) = g(f(x))
对全部x
in A
。如果任意两个函数的域/共域以这种方式匹配(换句话说,这样的一对函数“可以组合”),则可以为任意两个函数定义这种组合,并且我们通过声明“函数是可组合的”来描述这一点。
可组合性——在编程中
作为一个定性术语,我们经常在软件中使用“可组合性”来描述一组组合可以通过组合小东西来构建大东西的能力。从这个意义上说,程序员将函数(作为一个整体)描述为“非常可组合”,因为函数可以(并且在像 Haskell 这样的纯函数式语言中确实如此)包含整个程序的大小。
在软件中,我们还看到“可组合”一词更加以人为本的用法,它往往与“模块化”相关。当组件是无状态的、关注点被分离并且 API 的表面积较小时,就可以更轻松地编写程序而不会出错。我们赞扬这种设计的组件是“可组合的”——不仅仅是因为它们can被结合起来,但因为它们是easy结合正确地.
函数——编程中
我将使用稍微过时的术语“子例程”,因为我不知道用我们这个时代的用语来讨论这个问题的好方法。如果子例程不执行任何 IO(并且始终停止,并且不抛出......),那么它实现(或“是”)数学意义上的“函数”。 IO 子例程与函数表面上很相似,因为它们可能有输入和输出值,但相似之处仅此而已。我们第一次讨论的关于“函数组合”的讨论都不适用。
这就是我们遇到最棘手的语言困难的地方,因为“函数”这个词已经普遍用来指代any子例程,甚至是执行 IO 的子例程。 FP 爱好者往往会对此进行反对——人们会说“如果它支持 IO,那么它就不是一个函数”——但这场流行之战已经失败了,而且现在已经没有回头路了。在大多数编程环境中,所有子例程都称为“函数”,区分满足数学定义的函数的唯一方法是将它们称为“纯函数”。
建立这些定义后,让我们解决您的问题:
“可组合函数必须同时具有参数和返回值吗?”
关于这个问题有一些无聊的事情需要指出。首先,从技术上讲,Scala 中的每个函数都有一个返回类型。如果该类型是Unit
,为了简洁起见,它可能被省略,但它仍然是一个返回类型。
空值(0-arg)函数可以简单地转换为带有参数的等效函数。所以说真的,这并不重要。如果您需要使用参数来组合函数并且f
没有参数,你可以直接写_ => f
.
“这个功能会不会有副作用?”
只是语义上的争论。在Scala的背景下,最恰当的说法是它是一个Function
(或者从技术上讲可能是一个“方法”,具体取决于它的定义位置),但由于副作用,它不是一个纯函数。
“我们仍然认为它是‘可组合的’吗?”
有点。所有这些东西仍然以相当普遍的方式“组合在一起”,所以是的,它们确实在软件意义上组合在一起。尽管纯函数比非纯函数组合得更好。并且函数组合的数学概念不适用于非纯函数的子程序。
最后,如果你想知道它们是否真的在 Scala 中用compose
方法上Function1 http://www.scala-lang.org/api/current/#scala.Function1,你不需要Stack Overflow;只需询问编译器即可。