简体   繁体   English

Scala中的Currying:函数中的多个参数,包括类型的匿名函数(=> A)

[英]Currying in Scala: Multiple parameters in a function including an anonymous function of type ( => A)

What is the difference between these two code blocks? 这两个代码块有什么区别?

def measure[A](histogram: Histogram)(thunk: ⇒ A): A = {
  val start = RelativeNanoTimestamp.now
  try thunk finally {
    val latency = NanoInterval.since(start).nanos
    histogram.record(latency)
}

def measure[A](histogram: Histogram, thunk: ⇒ A): A = {
  val start = RelativeNanoTimestamp.now
  try thunk finally {
    val latency = NanoInterval.since(start).nanos
    histogram.record(latency)
}

Github Source Github来源

=> A is a lazy parameter. => A是一个惰性参数。 It will be evaluated when referred to in the function. 它将在函数中引用时进行评估。 It can be a function producing a value, or just a value. 它可以是产生值的函数,也可以只是一个值。

The main difference between single and multiple parameter lists as in your example: 单例和多参数列表之间的主要区别如下所示:

def measure[A](histogram: Histogram)(thunk: ⇒ A)
def measure[A](histogram: Histogram, thunk: ⇒ A)

(not considering implicits and type inference) is how you apply a function: (不考虑implicits和类型推断)是你如何应用函数:

scala> def f[A](i: Int)(p: => A): A = { p }
f: [A](i: Int)(p: => A)A

scala> f(1)(2)
res0: Int = 2

scala> f(1){ println("something") }
something

scala> f(1){
     |   println("test")
     | }
test

scala> def f2[A](i: Int, p: => A): A = { p }
f2: [A](i: Int, p: => A)A

scala> f2(1, 2)
res4: Int = 2

scala> f2(1, println("test"))
test

scala> f2(1, { println("test") })
test

See that f with multiple param lists allows us to write in this style: f(...){...} , while f2 is a bit less elegant if you have multiline code block as a second argument: f(..., {...}) . 看到带有多个参数列表的f允许我们用这种风格写: f(...){...} ,而如果你有多行代码块作为第二个参数, f2就不那么优雅了: f(..., {...})

Furthermore if you do lot's of currying/partial application then f2 is a bit easier to deal with than f : 此外,如果你做了很多currying /部分应用,那么f2f更容易处理:

scala> val f_withFirstArg = f(1) _
f_withFirstArg: (=> Nothing) => Nothing = <function1>

scala> val f2_withFirstArg = f2(1, _)
<console>:8: error: missing parameter type for expanded function ((x$1) => f2(1, x$1))
       val f2_withFirstArg = f2(1, _)
                                   ^

We have to specify parameter type explicitly, type inference fails short: 我们必须明确指定参数类型,类型推断失败简短:

scala> val f2_withFirstArg = f2(1, _: String)
f2_withFirstArg: String => String = <function1>

If you want to get technical about it, then it's worth pointing out that they are actually of a different type: 如果你想获得技术,那么值得指出它们实际上是不同的类型:

scala> :type f _
Int => ((=> Nothing) => Nothing)

scala> :type f2 _
(Int, => Nothing) => Nothing

f is a function that takes an Int and returns another function that takes type A and will produce type A . f是一个函数,它接受一个Int并返回另一个接受类型A并将产生类型A函数。 f2 is a function that takes 2 args: Int and A and returns A . f2是一个带2个参数的函数: IntA并返回A

It really depends on your code. 这真的取决于你的代码。 If you need to do lots of partial application or need less annotation due to type inference shortcomings then use multiple param lists. 如果由于类型推断缺点需要进行大量部分应用或需要较少的注释,则使用多个参数列表。 Otherwise there is no need to overcomplicate things and use regular single param list functions. 否则,不需要过度复杂化并使用常规的单个参数列表函数。

Finally you can always convert from one type of function to another as long as it makes sense: 最后,只要有意义,你总是可以从一种类型的函数转换为另一种函数:

scala> f2 _
res13: (Int, => Nothing) => Nothing = <function2>

scala> f2 _ curried
warning: there were 1 feature warning(s); re-run with -feature for details
res14: Int => ((=> Nothing) => Nothing) = <function1>

scala> f _ curried
<console>:9: error: value curried is not a member of Int => ((=> Nothing) => Nothing)
              f _ curried
                  ^

scala> f _ tupled
<console>:9: error: value tupled is not a member of Int => ((=> Nothing) => Nothing)
              f _ tupled
                  ^

scala> f2 _ tupled
warning: there were 1 feature warning(s); re-run with -feature for details
res17: ((Int, => Nothing)) => Nothing = <function1>

Notice that we can't make f curried because it already is. 请注意,我们不能让f令行禁止,因为它已经是了。 We can't make f tupled because it would not change anything. 我们不能让f tupled因为它不会改变任何事情。 However, we can convert f2 into f using curried : 但是,我们可以使用curriedf2转换为f

scala> :type f _
Int => ((=> Nothing) => Nothing)

scala> :type f2 _ curried _
Int => ((=> Nothing) => Nothing)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM