Scala 中柯里化的两种方式;每个用例是什么? [英] Two ways of currying in Scala; what's the use-case for each?

查看:22
本文介绍了Scala 中柯里化的两种方式;每个用例是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在讨论 多参数列表 在我维护的 Scala 风格指南中.我开始意识到有两种方式currying,我想知道什么是用例是:

I am having a discussion around Multiple Parameter Lists in the Scala Style Guide I maintain. I've come to realize that there are two ways of currying, and I'm wondering what the use cases are:

def add(a:Int)(b:Int) = {a + b}
// Works
add(5)(6)
// Doesn't compile
val f = add(5)
// Works
val f = add(5)_
f(10) // yields 15

def add2(a:Int) = { b:Int => a + b }
// Works
add2(5)(6)
// Also works
val f = add2(5)
f(10) // Yields 15
// Doesn't compile
val f = add2(5)_

风格指南错误地暗示它们是相同的,但它们显然不是.该指南试图说明创建的柯里化函数,虽然第二种形式不是按书"柯里化,但它仍然与第一种形式非常相似(尽管可以说更容易使用,因为你不需要_)

The style guide incorrectly implies these are the same, when they are clearly not. The guide is trying to make a point about created curried functions, and, while the second form is not "by-the-book" currying, it's still very similar to the first form (though arguably easier to use because you don't need the _)

对于使用这些形式的人来说,何时使用一种形式而不是另一种形式的共识是什么?

From those that use these forms, what's the consensus on when to use one form over the other?

推荐答案

多个参数列表方法

用于类型推断

具有多个参数部分的方法可用于辅助局部类型推断,方法是使用第一部分中的参数来推断类型参数,这些类型参数将为后续部分中的参数提供预期类型.标准库中的 foldLeft 就是典型的例子.

def foldLeft[B](z: B)(op: (B, A) => B): B

List("").foldLeft(0)(_ + _.length)

如果这是这样写的:

def foldLeft[B](z: B, op: (B, A) => B): B

必须提供更明确的类型:

One would have to provide more explicit types:

List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)

对于流畅的API

多参数节方法的另一个用途是创建一个看起来像语言结构的 API.调用者可以使用大括号代替圆括号.

For fluent API

Another use for multiple parameter section methods is to create an API that looks like a language construct. The caller can use braces instead of parentheses.

def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)

loop(2) {
   println("hello!")
}

将 N 个参数列表应用于具有 M 个参数部分的方法,其中 N _ 显式转换为函数,或使用 FunctionN[..] 的预期类型隐式转换.这是一项安全功能,有关背景信息,请参阅 Scala 参考中的 Scala 2.0 更改说明.

Application of N argument lists to method with M parameter sections, where N < M, can be converted to a function explicitly with a _, or implicitly, with an expected type of FunctionN[..]. This is a safety feature, see the change notes for Scala 2.0, in the Scala References, for an background.

柯里化函数(或者简单地说,返回函数的函数)更容易应用于 N 个参数列表.

Curried functions (or simply, functions that return functions) more easily be applied to N argument lists.

val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)

这种小小的便利有时是值得的.请注意,函数不能是参数类型,因此在某些情况下需要一个方法.

This minor convenience is sometimes worthwhile. Note that functions can't be type parametric though, so in some cases a method is required.

您的第二个示例是一个混合示例:一个返回函数的单参数节方法.

Your second example is a hybrid: a one parameter section method that returns a function.

柯里化函数还有什么用处?这是一个经常出现的模式:

Where else are curried functions useful? Here's a pattern that comes up all the time:

def v(t: Double, k: Double): Double = {
   // expensive computation based only on t
   val ft = f(t)

   g(ft, k)
}

v(1, 1); v(1, 2);

我们如何分享结果f(t)?一个常见的解决方案是提供 v 的矢量化版本:

How can we share the result f(t)? A common solution is to provide a vectorized version of v:

def v(t: Double, ks: Seq[Double]: Seq[Double] = {
   val ft = f(t)
   ks map {k => g(ft, k)}
}

丑!我们纠缠了不相关的问题——计算 g(f(t), k) 并映射一系列 ks.

Ugly! We've entangled unrelated concerns -- calculating g(f(t), k) and mapping over a sequence of ks.

val v = { (t: Double) =>
   val ft = f(t)
   (k: Double) => g(ft, k)       
}
val t = 1
val ks = Seq(1, 2)
val vs = ks map (v(t))

我们也可以使用返回函数的方法.在这种情况下,它更具可读性:

We could also use a method that returns a function. In this case its a bit more readable:

def v(t:Double): Double => Double = {
   val ft = f(t)
   (k: Double) => g(ft, k)       
}

但是如果我们尝试对具有多个参数部分的方法执行相同的操作,我们就会陷入困境:

But if we try to do the same with a method with multiple parameter sections, we get stuck:

def v(t: Double)(k: Double): Double = {
                ^
                `-- Can't insert computation here!
}

这篇关于Scala 中柯里化的两种方式;每个用例是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆