所以我在Scala中有这个功能:
def f(a: Int)(b: Int)(c: Double)(d: Double): Double = a * c + b * d
问题是使以下语句编译的三种类型是什么。
def g: <Type1> = f(1)(2)(3.0)
def h: <Type2> = f(1)(2)
def k: <Type3> = f(1)
我还是Scala的新手,我并不是真正理解currying的概念。也许通过一些解释回答这个问题对我很有帮助。感谢。
答案 0 :(得分:7)
首先,一个主要内容:带有两个参数a
和b
并返回值c
的函数可以被视为一个函数,它接受a
并返回需要b
并返回c
的函数。这种观点的改变&#34;被称为currying。
想象一个总结两个数字的函数。你给它2和3,它返回5.它可以被视为一个函数,它接受一个数字并将一个函数从一个数字返回一个数字。你给它一个2,它返回一个需要一些数字并加2的函数。
现在,您要求的某些类型:
// pseudocode!
def g: Double => Double
= f(1)(2)(3.0) // we supply three params and are left with only one, "d"
= (d: Double) => 1 * 3.0 + 2 * d // we comply with g's type
def h: Double => Double => Double // or (Double, Double) => Double
= f(1)(2) // we supply two params and are left with two more, "c" and "d"
= (c: Double)(d: Double) => 1 * c + 2 * d // we comply with h's type
def k: Double => Double => Double => Double // or (Double, Double, Double) => Double
= f(1) // we supply one param and are left with three more, "b", "c" and "d"
= (b: Double)(c: Double)(d: Double) => 1 * c + b * d // we comply with k's type
答案 1 :(得分:0)
理解IMO是Scala中最令人困惑的概念之一。这个术语本身来自函数式编程范式,并且根据wikipedia,是
翻译评估函数的技术 多个参数(或参数元组)用于评估a 函数序列,每个函数都有一个参数。
表示函数调用f(a, b, c)
由f(a)(b)(c)
表示。看起来像Scala?不完全是。这里我们有三个函数调用,每个调用返回另一个函数。 f
的类型(在Scala中)是Int => (Int => (Double => (Double => Double)))
。让我们看一下你的f
:
scala> def f(a: Int)(b: Int)(c: Double)(d: Double): Double = a * c + b * d
f: (a: Int)(b: Int)(c: Double)(d: Double)Double
如你所见,这里没有箭头。我们这里有一个带有多个参数列表的方法。方法没有价值,无法在任何地方分配或传递,它属于一个对象。另一方面,函数是一个对象,可以分配或传递给另一个方法或函数。在大多数情况下,方法不允许省略参数列表:
scala> f(0)
<console>:01: error: missing argument list for method f
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `f _` or `f(_)(_)(_)(_)` instead of `f`.
但有一个例外,因为错误消息暗示:如果f(0)
放置在功能上下文中,Scala将执行自动eta扩展,这意味着它会将您的方法转换为函数:
scala> val fl: (Int => (Double => (Double => Double))) = f(0)
fl: Int => (Double => (Double => Double)) = $$Lambda$1342/937956960@43c1614
其中eta-expansion意味着:
scala> val fl: (Int => (Double => (Double => Double))) = (b => (c => (d => f(0)(b)(c)(d))))
fl: Int => (Double => (Double => Double)) = $$Lambda$1353/799716194@52048150
将方法转换为curried函数的另一种(显式)方法是使用占位符(它会立即为您提供正确的类型):
scala> f _
res11: Int => (Int => (Double => (Double => Double))) = $$Lambda$1354/1675405592@4fa649d8
scala> f(0) _
res12: Int => (Double => (Double => Double)) = $$Lambda$1355/1947050122@ba9f744
还要注意:
def g: Int => (Double => (Double => Double)) = f(0)
实际上是
def g: Int => (Double => (Double => Double)) = (b => (c => (d => f(0)(b)(c)(d))))
即。它是一个方法g
,它可以动态创建一个函数并返回它。因此,g(0)
表示&#34;调用方法g
不带参数,取回函数并将其应用于0
&#34;。