在编写函数文字时,通过下划线Scala部分应用程序

时间:2017-06-16 00:59:38

标签: scala functional-programming composition currying partial-application

我正在编写函数文字,但与大多数示例不同,我看到我开始使用多参数函数,然后进行咖喱。

我有:

//types
case class Thing1(v: Double)
case class Thing2(v: Double)
case class Thing3(v: Double)
type Multiplier = Double

//functions
val f1 = (t: Thing1, m: Multiplier) => Thing2(m * t.v)
val f2 = (t: Thing2) => Thing3(t.v)

我想组合f1和f2来获得组合函数

Thing1 => (Multiplier => Thing3)

正如预期的那样,以下内容无法编译:

val fcomposed1 = f1.curried.andThen(f2) // does not compile

通过实验,我能够确定以下内容是否已编译并具有正确的签名:

val fcomposed2 = f1.curried(_:Thing1).andThen(f2)   

我已经阅读了各种来源,例如What are all the uses of an underscore in Scala?和可能相关的Why does Scala apply thunks automatically, sometimes?但不幸的是,我仍然无法一步一步地确定这里发生的事情及其原理。

此外,我希望上面分成两个表达式与fcomposed2完全相同,但是第二个表达式不能编译:

val f1partial = f1.curried(_:Thing1)
val fcomposed3 = f1partial.andThen(f2) // does not compile - same error as fcomposed1

看起来f1partial返回与f1.curried相同的签名,这让我更加想知道早期的fcomposed2是如何工作的。

有人可以一步一步解释这两种行为吗?

1 个答案:

答案 0 :(得分:3)

这里,_充当lambda表达式的语法糖,但是你可能没想到它。

f1.curried的类型为Thing1 => Multiplier => Thing2

f1.curried(_:Thing1){ x: Thing1 => f1.curried(x) }相同。由于f1.curried(x)的结果类型为Multiplier => Thing2,因此整个表达式的最终类型仍为Thing1 => Multiplier => Thing2。因此,对结果(andThen(f2))调用f1partial无效,因为函数f2(Thing2)的输入类型与前一个函数的输出不同{{{ 1}})。

相比之下,Multiplier => Thing2扩展为f1.curried(_:Thing1).andThen(f2){ x: Thing1 => f1.curried(x).andThen(f2) }评估类型f1.curried(x),如前所述,因此可以在其上调用Multiplier => Thing2,从而产生andThen(f2)。那么整个表达式的计算结果为Multiplier => Thing3

如果您考虑这两种表达方式之间的差异,也许会更清楚:

Thing1 => Multiplier => Thing3