Scala高阶函数有点困惑

时间:2013-11-06 07:59:09

标签: scala functional-programming currying higher-order-functions

我在Worksheet中运行了下面的Scala代码:

package src.com.sudipta.week2.coursera
import scala.math.abs
import scala.annotation.tailrec

object FixedPoint {
  println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet

  val tolerance = 0.0001                          //> tolerance  : Double = 1.0E-4
  def isCloseEnough(x: Double, y: Double): Boolean = {
    abs((x - y) / x) / x < tolerance
  }                                               //> isCloseEnough: (x: Double, y: Double)Boolean
  def fixedPoint(f: Double => Double)(firstGuess: Double): Double = {
    @tailrec
    def iterate(guess: Double): Double = {
      val next = f(guess)
      if (isCloseEnough(guess, next)) next
      else iterate(next)
    }
    iterate(firstGuess)
  }                                               //> fixedPoint: (f: Double => Double)(firstGuess: Double)Double

  def myFixedPoint = fixedPoint(x => 1 + x / 2)(1)//> myFixedPoint: => Double
  myFixedPoint                                    //> res0: Double = 1.999755859375

  def squareRoot(x: Double) = fixedPoint(y => (y + x / y) / 2)(1)
                                                  //> squareRoot: (x: Double)Double
  squareRoot(2)                                   //> res1: Double = 1.4142135623746899

  def calculateAverate(f: Double => Double)(x: Double) = (x + f(x)) / 2
                                                  //> calculateAverate: (f: Double => Double)(x: Double)Double
  def myNewSquareRoot(x: Double): Double = fixedPoint(calculateAverate(y => x / y))(1)
                                                  //> myNewSquareRoot: (x: Double)Double
  myNewSquareRoot(2)                              //> res2: Double = 1.4142135623746899
}

令我困惑的是:

  • Scala工作表显示在我的fixedPoint函数
  • 下面
  

fixedPoint :( f:Double =&gt; Double)(firstGuess:Double)Double

这是什么?这是函数类型/函数定义还是我缺少这个术语? 基本上我怎么用英语解释这个功能?

  • Scala工作表显示在我的calculateAverate函数
  • 下面
  

calculateAverate:(f:Double =&gt; Double)(x:Double)Double

但它看起来我的函数的返回类型是Double,但我期待Double =&gt;双。原因是我将使用fixedPoint,它需要Double =&gt;双倍如下:

  

def myNewSquareRoot(x:Double):Double = fixedPoint(calculateAverate(y   =&GT; x / y))(1)

请帮助我更清楚地了解高阶函数/ Currying。提前谢谢。

2 个答案:

答案 0 :(得分:4)

fixedPoint: (f: Double => Double)(firstGuess: Double)Double

这里的任务是找到功能的固定点,任务的应用将是我们众所周知的平方根与牛顿方法

牛顿方法的平方根:

Calculates the square root of parameter x

def sqrt(x: Double): Double = ...

实现这一目标的经典方法是使用牛顿方法的连续近似。

计算sqrt(x):

  1. 从初始估计开始y(让我们选择y = 1)。
  2. 通过取y和x / y的平均值反复改进估计。
  3. 示例:x=2

      Estimation               Quotient                    Mean
        1                       2/1=2                       1.5
       1.5                      2/1.5=1.333                1.4167
      1.4167                    2/1.4167=1.4118            1.4142
      1.4142 so on
    

    首先,定义一个计算一个迭代步骤的函数

    def sqrtIter(guess: Double, x: Double): Double =
    if (isGoodEnough(guess, x)) guess
    else sqrtIter(improve(guess, x), x)
    

    第二次,定义一个改进的函数以改进估计和一个检查终止的测试:

    def improve(guess: Double, x: Double) =
    (guess + x / guess) / 2
    def isGoodEnough(guess: Double, x: Double) =
    abs(guess * guess - x) < 0.001
    

    第三次,定义sqrt函数:

    def sqrt(x: Double) = srqtIter(1.0, x)
    

    使用您的固定点功能我们还计算数字的平方根

    首先看看什么是定点:

    如果number x

    f(x) = x被称为函数的固定点

    对于某些函数,我们可以通过从初始估计开始,然后以重复方式应用f来定位固定点。

    x, f(x), f(f(x))
    

    这导致以下用于查找固定点的功能:

    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)
    }
    

    在这个公式中,fixedPoint是一个返回另一个函数的函数,即专用函数iterate

    此处fixedPoint

    def fixedPoint(f: Double => Double)(firstGuess: Double)
    

    函数fixedPoint应用于函数f: Double => Double。所结果的 然后将函数应用于第二个参数

    (firstGuess: Double)
    

    这种表示法是可行的,因为函数应用程序关联到左侧。那是, 如果args1和args2是参数列表,那么f(args1)(args2)相当于(f(args1))args2

    在你的程序中,第一个参数是函数,其中输入类型为Double,返回类型为Double,然后将此函数应用于猜测

    重新定义平方根函数。

    让我们从sqrt的规范开始:

    sqrt(x) = the y such that y*y = x
            = the y such that y = x / y
    

    因此,sqrt(x)是函数y => x / y的固定点。这表明

    sqrt(x) 
    

    可以通过定点迭代计算:

    def sqrt(x: double) = fixedPoint(y => x / y)(1.0)
    

    这是一个很长的答案,但我认为这将有助于您理解这个概念

答案 1 :(得分:2)

功能

def fixedPoint (f: Double => Double)(firstGuess: Double):Double

是一个函数定义,它有两个参数:

  1. 一个函数“f”,它接受Double类型的参数,该参数返回Double
  2. 名为“firstGuess”的Double
  3. 并返回Double。将单个参数分离到它们自己的括号组允许该函数用于currying:

    def mySqrtCalc(x:Double)(firstGuess:Double):Double = {...}
    
    val mySqrtFunc = mySqrtCalc(2.0) _
    
    val v = mySqrtFunc(1) // parameter firstGuess is set to 1
    

    除了currying的能力,这相当于未经证实的版本

    def fixedPoint (f: Double => Double,firstGuess: Double):Double
    

    对你来说可能更熟悉。

    calculateAverate的结果是一个Double,因为你将传递函数f的结果加到带x的x,它给你一个Double,因为f是一个函数Double => Double

    您在calculateAverate方法体中以咖喱方式使用myNewSquareRoot方法,首先只给出两个参数中的第一个,省略第二个参数,这是从外部获取的fixedPoint方法。省略calculateAverate的第二个参数会为您提供Double=>Double方法所需的方法fixedPoint

    您可以插入一些println(s"<methodname> value=$value")来观察执行流程并理解方法调用顺序。