我正在通过火花的测试代码。虽然我理解下面给出的函数背后的逻辑
它意味着什么,以下语法定义有什么好处?
测试代码
def withStreamingContext[R](ssc: StreamingContext)(block: StreamingContext => R): R = {
try {
block(ssc)
} finally {
try {
ssc.stop(stopSparkContext = true)
} catch {
case e: Exception =>
logError("Error stopping StreamingContext", e)
}
}
}
为什么必须这样定义?为什么不能
def withStreamingContext[R](ssc: StreamingContext,block: StreamingContext => R): R =
答案 0 :(得分:3)
嗯,它可以。将参数分成两个或多个参数列表称为currying。这样,双参数函数可以转换为一个函数,该函数接受一个参数并返回一个接受一个参数并返回结果的函数。这就是您发布的代码中发生的情况。每个 n - 参数函数都可以看作 n 1参数函数(事实上,在Haskell中,所有函数都被这样处理)。
请注意,Scala还有一个部分应用函数的概念,归结为同样的事情。 PAF和currying都允许您只传递一个参数子集,从而接收一个剩余的函数。
例如,
def sum(x: Int, y: Int) = x + y
可以用咖喱,然后你可以说,例如:
def sum(x: Int)(y: Int) = x + y
def addTwo = sum(2) _ // type of addTwo is Int => Int
为您提供相同的功能,但应用了第一个参数。使用PAF,它将是
def sum(x: Int, y: Int) = x + y
def addTwo = sum(2, _: Int)
答案 1 :(得分:1)
使用起来更方便:
withStreamingContext(ssc) {
doSomething()
doSomethingElse()
}
VS
withStreamingContext(ssc, { doSomething(); doSomethingElse() })
答案 2 :(得分:1)
首先
def a(x: Int)(y: Int) = x * y
是
的语法糖def a(x: Int) = (y: Int) => x * y
这意味着您定义了一个返回函数的方法(关闭x
)
您可以在没有所有参数列表的情况下调用此方法并传递返回的函数。您也可以部分应用任何其他方法,但我认为这种语法更清晰。
此外,可以使用表达式语法调用具有一元参数列表的函数/方法。
withStreamingContext(ssc) {
// your code block passed to function
}
答案 3 :(得分:1)
这种声明功能称为currying。它由MosesSchönfinkel独立介绍,后来由Haskell Curry从它的名字所在地引入。这个概念实际上源于数学,然后被引入计算机科学。
经常与部分功能应用混淆;主要区别在于对部分应用函数的调用会立即返回结果,而不是“currying”链中的另一个函数。
scala> def foo (x:Int, y:Int, z:Int) : Int = x + y + z
foo: (x: Int, y: Int, z: Int)Int
scala> val pa = foo(1, _:Int, _:Int)
pa: (Int, Int) => Int = <function2>
scala> pa(2,3)
res0: Int = 6
相反,给定f:(x,y,z) -> n
,currying产生f':x -> (y -> (z -> n))
。换句话说,将每个参数依次应用于上一次调用返回的单个参数函数。
在调用f'(1)
之后,返回一个接受单个参数并返回另一个函数的函数,而不是一个带有两个参数的函数。
相比之下,部分函数应用程序指的是将多个参数固定到函数的过程,从而产生较小arity的另一个函数。这两者经常混为一谈。
已经提到了currying的好处/优点elsewhere。你遇到的主要问题是理解语法及其起源,已经解释过了。