我在Scala compose
和andThen
方法上关注教程 Pattern matching & functional composition 。有这样一个例子:
scala> def addUmm(x: String) = x + " umm"
scala> def addAhem(x: String) = x + " ahem"
val ummThenAhem = addAhem(_).compose(addUmm(_))
当我尝试使用它时,我收到错误:
<console>:7: error: missing parameter type for expanded function ((x$1) => addAhem(x$1).compose(((x$2) => addUmm(x$2))))
val ummThenAhem = addAhem(_).compose(addUmm(_))
^
<console>:7: error: missing parameter type for expanded function ((x$2) => addUmm(x$2))
val ummThenAhem = addAhem(_).compose(addUmm(_))
^
<console>:7: error: type mismatch;
found : java.lang.String
required: Int
val ummThenAhem = addAhem(_).compose(addUmm(_))
然而,这有效:
val ummThenAhem = addAhem _ compose addUmm _
甚至
val ummThenAhem = addAhem _ compose addUmm
教程中的代码有什么问题?后一个表达式不是没有括号的第一个表达式吗?
答案 0 :(得分:49)
嗯,这个:
addUhum _
是一个eta扩展。它将方法转换为函数。另一方面,这个:
addUhum(_)
是一个匿名函数。实际上,它是一个部分函数应用程序,因为该参数未被应用,并且整个事物被转换为函数。它扩展到:
x => addUhum(x)
扩展的确切规则有点难以解释,但基本上,函数将在最里面的表达式分隔符处“开始”。例外是部分函数应用程序,其中“x”移到函数外部 - 如果使用_
代替参数。
无论如何,这是它扩展的方式:
val ummThenAhem = x => addAhem(x).compose(y => addUmm(y))
唉,类型推断器不知道x或y的类型。如果您愿意,可以使用参数-Ytyper-debug
准确查看其尝试的内容。
答案 1 :(得分:41)
addAhem
是一种方法。 compose
方法是在函数上定义的。 addAhem _
会将addAhem
从方法转换为函数,因此可以在其上调用compose
。 compose
期望函数作为它的参数。您通过将addUmm
转换为具有addUmm
的函数来为它提供方法addUmm _
(可以省略下划线,因为编译器可以在知道某个方法时自动将方法转换为函数功能预计无论如何)。所以你的代码:
addAhem _ compose addUmm
与
相同(addAhem _).compose(addUmm)
但不是
addAhem(_).compose(addUmm(_))
PS 我没看到你提供的链接。
答案 2 :(得分:5)
来自compose
文档:
使用此函数在新的Function1中组合Function1的两个实例 函数最后应用。
所以你应该写
scala> val ummThenAhem = (addAhem _).compose(addUmm _)
ummThenAhem: String => java.lang.String = <function1>
将addAhem
和addUmm
视为部分应用的功能(即function1
)
scala> addAhem _
res0: String => java.lang.String = <function1>
答案 3 :(得分:2)
我相信该教程是为早期版本的Scala编写的(可能是2.7.7或更早版本)。从那时起编译器中发生了一些变化,即类型系统的扩展,现在导致类型推断失败:
addUhum(_).compose(addAhem(_))
如果你只写:
,那么解除函数仍然可以使用该语法addUhum(_)