我正在编写函数文字,但与大多数示例不同,我看到我开始使用多参数函数,然后进行咖喱。
我有:
//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是如何工作的。
有人可以一步一步解释这两种行为吗?
答案 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