我是scala的新手,正在学习scala功能开发的课程。下面的代码片段解释了currying
import math.abs
object exercise{
val tolerance = 0.0001
def isCloseEnough(x: Double, y: Double) = abs((x -y)/x)/x < tolerance
def fixedPoint(f: Double => Double)(firstGuess: Double) = {
def iterate(guess: Double):Double = {
val next = f(guess)
if ( isCloseEnough(guess, next)) next
else iterate(next)
}
iterate(firstGuess)
}
def averageDamp(f: Double => Double)(x: Double) = ( x + f(x))/2
def sqrt(x: Double) = fixedPoint( averageDamp(y => x/y))(1)
}
我无法理解代码的以下部分
fixedPoint( averageDamp(y => x/y))(1)
我知道averageDamp函数有2个参数(一个是函数,另一个是x的值)但是当它从fixedPoint调用时,我们不传递x的值。所以我假设它正在创建一个部分函数,它被发送回sqrt,其中x的值从sqrt(x:Double)agrument传递。所以我做了以下无法编译的函数
def noIdea(x: Double) = averageDamp( y => x/y)
有人可以向我解释一下吗?
答案 0 :(得分:4)
创建一个像这样的curried函数只有在你将它作为参数传递给另一个函数或者在其他需要函数的情况下才有效。由于fixedPoint
收到一个函数,你可以简单地写:
fixedPoint( averageDamp(y => x/y))(1)
当你想要创建一个curried函数时,Scala会让你添加_
或(_)(_)
以确认你的意图:
def noIdea(x: Double) = averageDamp( y => x/y) _
在这种情况下避免它的另一种方法是指定noIdea
的返回类型:
def noIdea(x: Double): Double => Double = averageDamp( y => x/y)
_
只是一种确保你真的想要创建一个函数并且不会忘记传递额外参数的方法。
答案 1 :(得分:2)
您需要提供下划线才能在未应用的方法上触发eta expansion。方法没有值,因此必须将它们转换为函数对象才能分配给变量。当Scala知道应该将未应用的方法解释为函数对象时,会自动触发eta扩展。在其他情况下,您需要使用下划线手动触发扩展。
不确定您的Scala版本是什么,但2.11.7非常清楚。这是一个带缩放功能的简单示例:
scala> def my_scaler(sc: Double)(x: Double): Double = sc*x
my_scaler: (sc: Double)(x: Double)Double
scala> def my_doubler = my_scaler(2d) // no eta exp
<console>:13: error: missing argument list for method my_scaler
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `my_scaler _` or `my_scaler(_)(_)` instead of `my_scaler`.
def my_doubler = my_scaler(2d)
^
scala> def my_doubler = my_scaler(2d) _ // manual eta exp
my_doubler: Double => Double
scala> my_doubler(10d)
res1: Double = 20.0
scala> def my_tripler: Double => Double = my_scaler(3d) // auto eta exp
my_tripler: Double => Double
scala> my_tripler(10d)
res2: Double = 30.0