2011-09-21 40 views
42

我正在按照斯卡拉composeandThen方法的教程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 

教程中的代码有什么问题?不是后者的表达与没有括号的第一个表达式相同吗?

回答

38

addAhem是一种方法。 compose方法在函数上定义。 addAhem _addAhem从方法转换为函数,因此可以调用composecompose需要一个函数,因为它是参数。通过将addUmm转换为addUmm _(下划线可以省略,因为编译器可以在知道函数预期时自动将函数转换为函数),您正在给它一个方法addUmm。所以,你的代码:

addAhem _ compose addUmm 

相同

(addAhem _).compose(addUmm) 

但不

addAhem(_).compose(addUmm(_)) 

PS 我不敢看你提供的链接。

+0

为了完整起见,andThen例子是这样的:。 'VAL ahemThenUmm = addAhem(_)andThen(addUmm(_))' 时,它应该像 'VAL ahemThenUmm1 =(addAhem _)andThen(addUmm )' –

+0

我不太确定用圆括号写的部分;编译器*不会*将方法自动转换为函数,至少对于Scala 2.10.2来说。解决方法是声明'addAhem'和'addUmm'作为函数,这样'compose'或'和Then'就不用'_'工作。 –

5

compose文档:

Composes two instances of Function1 in a new Function1, with this function applied last.

,所以你应该写

scala> val ummThenAhem = (addAhem _).compose(addUmm _) 
ummThenAhem: String => java.lang.String = <function1> 

治疗addAhemaddUmm为部分应用功能(即function1

scala> addAhem _ 
res0: String => java.lang.String = <function1> 
2

我相信本教程是为早期版本的Scala编写的(可能是2.7.7或更早版本)。目前已在编译器的一些变化从那时起,即扩展类型系统,这导致现在的类型推断失败的:

addUhum(_).compose(addAhem(_)) 

提升到一个功能仍然有效,与语法如果你只是写:

addUhum(_) 
45

那么,这:

addUhum _ 

是ETA扩张。它将方法转换为函数。另一方面,这个:

addUhum(_) 

是一个匿名函数。实际上,它是一个部分函数应用程序,因为这个参数没有被应用,整个事物被转换成一个函数。它扩展为:

x => addUhum(x) 

扩张的确切规则有点难以解释,但是,基本上,该函数将“开始”,在最里面的表达式分隔符。例外是部分功能应用程序,其中“x”移到功能外 - 如果使用_代替参数。

无论如何,这是它是如何扩展:

val ummThenAhem = x => addAhem(x).compose(y => addUmm(y)) 

唉,类型inferencer不知道X或Y的类型。如果您愿意,您可以使用参数-Ytyper-debug查看它所尝试的内容。