Scala 高阶函数有点困惑

标签 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
}

让我困惑的是:

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

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

这是什么?这是函数类型/函数定义还是我遗漏了这个术语? 基本上我如何用英语解释这个功能?

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

calculateAverate: (f: Double => Double)(x: Double)Double

但在我看来我的函数的返回类型是 Double,但我期待的是 Double => Double。原因是我将把它与 fixedPoint 一起使用,它需要 Double => Double 如下所示:

def myNewSquareRoot(x: Double): Double = fixedPoint(calculateAverate(y => x / y))(1)

请帮助我更清楚地理解高阶函数/柯里化(Currying)。提前致谢。

最佳答案

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

这里的任务是找到函数的不动点,任务的应用将是我们众所周知的用牛顿法求平方根

牛顿法平方根:

计算参数 x 的平方根

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

实现这一点的经典方法是使用牛顿法逐次逼近。

计算 sqrt(x):

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

示例: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)

其次,定义一个函数 improve 来改进估计和检查终止的测试:

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)

使用您的 Fixedpoint 函数,我们还可以计算数字的平方根

先看看什么是不动点:

如果 f(x) = x

数 x 称为函数 f 的不动点

对于某些函数 f,我们可以通过从初始估计开始然后以重复的方式应用 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

此处固定点

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)

这是一个很长的答案,但我认为它会帮助你理解这个概念

关于Scala 高阶函数有点困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19806760/

相关文章:

scala - 如果应用程序运行很长时间,则缺少类

将文字或变量分配给 Char 时的 Scala 行为

scala - 如何在 Scalatra 中获取 post 请求的正文?

programming-languages - 命令式语言中可以使用哪些函数式语言技术?

c# - 当我在 c# 中的一个类中定义我的所有函数时,我是否在进行函数式编程?

scala - 带柯里化(Currying)的默认参数

javascript - 分支是柯里化(Currying)的必要特征吗?

scala - Scala:构建特征和类的复杂层次结构

typescript - 使用 TypeScript,我可以键入 getProperty<T, K extends keyof T> 的柯里化(Currying)版本吗

javascript - 如何根据程序的实现导出程序的 HM 类型?