Scala 柯里化示例

Scala currying example

我是 scala 的新手,正在学习 scala 功能开发的 coursera 课程。下面的代码片段解释了柯里化

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 函数有两个参数(一个是函数,另一个是 x 的值)但是当它从 fixedPoint 调用时,我们不传递 x 的值。所以我假设它正在创建一个部分函数,​​该函数被发送回 sqrt,其中 x 的值从 sqrt(x: Double) agrument 传递。所以我做了以下无法编译的函数

def noIdea(x: Double) = averageDamp( y => x/y)

谁能给我解释一下?

您需要提供下划线才能在未应用的方法上触发 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

只有当您将它作为参数传递给另一个函数或在其他需要函数的情况下,才能创建像这样的柯里化函数。由于 fixedPoint 收到一个函数,您可以简单地写:

fixedPoint( averageDamp(y => x/y))(1)

当你想创建一个柯里化函数时,Scala 会让你添加一个 _(_)(_) 来确认你的意图:

def noIdea(x: Double) = averageDamp( y => x/y) _

在这种情况下避免它的另一种方法是为 noIdea 指定 return 类型:

def noIdea(x: Double): Double => Double  = averageDamp( y => x/y)

_ 只是一种确保您确实想要创建函数并且没有忘记传递额外参数的方法。