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

Scala 在编写函数文字时通过下划线缩放部分应用程序,scala,functional-programming,composition,currying,partial-application,Scala,Functional Programming,Composition,Currying,Partial Application,我正在编写函数文本,尽管与我所看到的大多数示例不同,我从一个多参数函数开始,然后用curry 我有: //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 =

我正在编写函数文本,尽管与我所看到的大多数示例不同,我从一个多参数函数开始,然后用curry

我有:

//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 f1partial = f1.curried(_:Thing1)
val fcomposed3 = f1partial.andThen(f2) // does not compile - same error as fcomposed1
通过实验,我发现以下内容确实可以编译,并且具有fcomposed的正确签名:

val fcomposed2 = f1.curried(_:Thing1).andThen(f2)   
我已经阅读了很多相关的资料,但不幸的是,我仍然无法一步一步地弄清楚这里到底发生了什么,以及它为什么会起作用

此外,我希望上述分为两个表达式的表达式的工作方式与fcomposed2相同,但第二个表达式不编译:

val fcomposed1 = f1.curried.andThen(f2) // does not compile
val f1partial = f1.curried(_:Thing1)
val fcomposed3 = f1partial.andThen(f2) // does not compile - same error as fcomposed1
看起来f1partial返回的签名与f1.curried相同,这让我进一步想知道早期的fcomposed2是如何工作的


有人能一步一步地解释这两种行为吗?

在这里,
\uu
充当lambda表达式的语法糖,但其程度可能超出了您的预期

f1.curried
具有类型
Thing1=>Multiplier=>Thing2

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

相比之下,
f1.curried(u:Thing1)。然后(f2)
扩展到
{x:Thing1=>f1.curried(x)。然后(f2)}
f1。curried(x)
计算为类型
Multiplier=>Thing2
,如前所述,因此您可以调用
然后再调用(f2)
,从而得到
Multiplier=>Thing3
。因此,整个表达式的计算结果为
Thing1=>Multiplier=>Thing3

如果你想一想这两种表达方式之间的区别,也许会更清楚:

val fcomposed1 = { x: Thing1 => f1.curried(x).andThen(f2) } // valid
val fcomposed2 = { x: Thing1 => f1.curried(x) }.andThen(f2) // error

谢谢,这看起来像是答案,不过我还得多读几遍才能真正领会!PS:第二段中缺少一个右大括号,即“扩展到”后的代码块。显示表达式如何扩展的答案以及清楚解释最终差异的最后两行非常好,谢谢。尽管Scala确实以不同的方式扩展了这两个表达式(fcomposed2和fcomposed3,请参考我的问题),但我仍然觉得有点奇怪——这可能需要更多的阅读/思考才能理解。额外注意:一旦我了解了下划线lambda表达式的情况(毕竟不是部分应用程序),我发现并质疑值得一读的书。