我正在尝试学习Scala,我很困惑何时使用currying函数而非部分应用函数。
我很确定这些概念并不是多余的,但我看不出不同方法的真正目的。
我正在尝试使用此代码:
解决方案使用currying:
object CurryTest extends App {
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
if (xs.isEmpty) xs
else if (p(xs.head)) xs.head :: filter(xs.tail, p)
else filter(xs.tail, p)
def modN(n: Int)(x: Int) = ((x % n) == 0)
val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2)))
println(filter(nums, modN(3)))
}
解决方案使用部分应用的功能:
object PartialFunctionTest extends App {
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
if (xs.isEmpty) xs
else if (p(xs.head)) xs.head :: filter(xs.tail, p)
else filter(xs.tail, p)
def modN(n: Int, x: Int) = ((x % n) == 0)
val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2,_)))
println(filter(nums, modN(3,_)))
}
两者都给出了相同的结果:
List(2, 4, 6, 8)
List(3, 6)
这些不同的方法是否相同?
有人可以告诉我,每个人的最佳用例是什么?
答案 0 :(得分:1)
这是一种风格独特的选择。在你的情况下,它没有真正的区别,但我认为第一个替代多个参数列表看起来更好。
在风格方面,当方法用于以咖喱方式使用时,请使用咖喱功能。当您需要为不是为其设计的函数时,请使用部分应用程序。
在某些情况下,您必须使用一个而不是另一个。例如,多个参数列表允许您在两个列表中使用var args
def ex1(ints: Int*)(strings: String*)
如果您有通用类型,这些类型可以从一个列表流向下一个
def ex2[A](input: A)(func: A => A): A = func(input)
ex2(1)(x => "Hello " + x) //compile error, A is Int from first parameter list
def ex2a[A](input: A, func: A => A): A = func(input)
ex2a(1, x => "Hello " + x) //compiles and returns "Hello 1", A is Any because all parameters in the same list are used to determine it's type
在某些情况下,您可能需要使用部分应用程序。例如,在case类构造函数中,如果您尝试进行curry,则只有第一个参数列表成为case类字段的一部分。
case class ex3(a: Int, b:Int)
ex3(1, 2) == ex3(1,3) //false
val y: Int => ex3 = ex3(1,_)
y(2) == y(2) //true
y(2) == y(3) //false
case class ex3a(a: Int)(b:Int)
ex3a(1)(2) == ex3a(1)(3) //true
val x: Int => ex3a = ex3a(1)
x(1) == x(1) //true
x(1) == x(2) //true