`
wbj0110
  • 浏览: 1598306 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Scala 中的函数式编程基础(二)

阅读更多

2. Higher Order Functions

把其他函数作为参数或者作为返回值,就是 higher order functions,python 里面也可以看到这样使用的情形。在酷壳上的博客有一个例子就是将函数作为返回值。

2.1 匿名函数

在 python 里边叫 lambda 函数,常常与 map(), filter(), reduce() 联合使用,前面也写过一篇这样的博客。

举一个 scala 的 reduce 的例子,f: Int => Int 表示 f 是一个整数映射到整数的函数,计算下面公式:

bn=af(n)
def sum(f: Int => Int, a: Int, b: Int): Int = {
    def loop(a: Int, acc: Int): Int =
        if (a > b) acc
        else loop(a + 1, f(a) + acc)
    loop(a, 0)
}
def sumInts(a: Int, b: Int) = sum(x => x, a, b)  // f(n)=n
def sumCubes(a: Int, b: Int) = sum(x => x * x * x, a, b)  // f(n)=n*n*n
println(sumInts(2, 7))   //求和
println(sumCubes(3, 10)) //求立方和

2.2 currying

把一个函数的多个参数分解成多个函数, 然后把函数多层封装起来,每层函数都返回一个函数去接收下一个参数这样,可以简化函数的多个参数。

// sum 返回函数 sumF,风格与 python 相似
  def sum(f: Int => Int): (Int, Int) => Int = {
    def sumF(a: Int, b:Int): Int =
      if (a > b) 0 else f(a) + sumF(a + 1, b)
    sumF
  }           
  def sumInts = sum(x => x)      
  def sumCubes = sum(x => x * x * x) 

  sumInts(1, 5)            //> res0: Int = 15
  sumCubes(1, 5)           //> res1: Int = 225
  sum(x=>x)(1, 5)          //> res2: Int = 15
  (sum(x=>x))(1, 5)        //> res3: Int = 15

更为简短的写法:

def sum(f: Int => Int)(a: Int, b: Int): Int =
  if (a > b) 0 else f(a) + sum(f)(a + 1, b)

sum(x => x)(1, 5)  // 第一个()相当于创建了一个匿名函数

mapReduce 实现过程包括 map 一一映射函数和 reduce 函数及单位元素 zero(乘为1,加为0),参数包括序列区间 [a, b] 两个参数,假设我们求 [a, b] 区间上所有元素的平方和:

def mapReduce(map: Int => Int, reduce: (Int, Int) => Int, zero: Int)(a: Int, b: Int): Int = 
  if (a > b) zero
  else reduce(map(a), mapReduce(map, reduce, zero)(a + 1, b))
def sumOfSquare(a: Int, b: Int) = mapReduce(x => x*x, (x, y) => x + y, 0)(a, b) //这里确定了三个,留下参数ab

比如求立方和,四次方和等,更灵活的用法是 map 和 reduce 可以先指定一个reduce(都是sum),使用时再指定另一个(map),代码就不贴了。总之,所有mapreduce设置,包括map,reduce, zero, a, b都可以无序设置,替换组合成包含不同参数列表的新函数。

2.3 类

构造一个分数(rational)类,实现加减、比大小等基本功能。

object rationals {
  val x = new Rational(1, 3)              //> x  : week3.Rational = 1/3
  val y = new Rational(5, 7)              //> y  : week3.Rational = 5/7
  val z = new Rational(3)                 //> z  : week3.Rational = 3/1
  x.numer                                 //> res0: Int = 1
  x.sub(y).sub(z)                         //> res1: week3.Rational = 71/-21
  y.add(y)                                //> res2: week3.Rational = 10/7
  x.less(y)                               //> res3: Boolean = true
  x.max(y)                                //> res4: week3.Rational = 5/7
}

class Rational(x: Int, y: Int) {
  require(y != 0, "denomitor must be nonzero")

  // scala 的构造函数就是执行body
  def this(x: Int) = this(x, 1) // 第二种构造函数, 补全到第一种

  private def gcd(a: Int, b: Int): Int =
    if (b==0) a else gcd(b, a % b) //private函数,求最大公约数

  val numer = x / gcd(x, y)  // 每次构造新类,都化简
  val denom = y / gcd(x, y)  // val,gcd函数只计算一次

  def add(that: Rational) =
    new Rational(
      numer * that.denom + denom * that.numer, // 交叉相乘相加
      denom * that.denom)

  def neg: Rational = new Rational(-numer, denom)

  def sub(that: Rational) = add(that.neg)

  def less(that: Rational) = numer * that.denom < that.numer * denom

  def max(that: Rational) = if (this.less(that)) that else this // this 关键字,表示使用该method的object

  override def toString = numer + "/" + denom // 每次打印类的格式
}

2.4 操作符

c++里面有操作符的重载,在scala里面技术层面上来说没有操作符这个概念。比如 1 + 2 实际是 1.+(2)。 + 是对象 1 的一种方法。Scala 实现 1 + 2 这种写法需要两种技术,以上面的例子来分析:

  1. 上面的例子中 r.add(s) 可以写成 r add s,任何只包含一个参数的方法都可以写成这样的形式,这种做法叫Infix Notation
  2. 但问题是,现在整数的加法是 a + b,分数的加法如果是 a add b,风格不一致。还有一个方法叫 Relaxed Identifiers。大概意思是标志符不仅可以是字母开头的字符串组成,还可以是运算符(如果后面是冒号,加至少一个空格,否则会将冒号也看出标志的一部分)。

实现与整数加法风格一致的分数运算,代码如下:

package week3

object rationals {
  val x = new Rational(1, 3)              //> x  : week3.Rational = 1/3
  val y = new Rational(5, 7)              //> y  : week3.Rational = 5/7
  val z = new Rational(3)                 //> z  : week3.Rational = 3/1
  -x                                      //> res0: week3.Rational = 1/-3
  x - y - z                               //> res1: week3.Rational = 71/-21
  y + y                                   //> res2: week3.Rational = 10/7
  x < y                                   //> res3: Boolean = true
  x * x + z * z                           //> res4: week3.Rational = 82/9
}

class Rational(x: Int, y: Int) {
  require(y != 0, "denomitor must be nonzero")

  def this(x: Int) = this(x, 1)
  private def gcd(a: Int, b: Int): Int =
    if (b==0) a else gcd(b, a % b)

  val numer = x / gcd(x, y)
  val denom = y / gcd(x, y)

  def + (that: Rational) =
    new Rational(
      numer * that.denom + denom * that.numer,
      denom * that.denom)

  def unary_- : Rational = new Rational(-numer, denom) // unary_:一元运算符和二元运算符不同,一元要特地指出

  def - (that: Rational) = this + -that

  def < (that: Rational) = numer * that.denom < that.numer * denom

  def * (that: Rational) = new Rational(numer * that.numer, denom * that.denom)

  override def toString = numer + "/" + denom // 打印类的格式
}

注意到上面代码中 x*x + z*z 没用括号也能计算出准确的结果,这是因为 scala 通用一套根据标识符确定运算优先级的规则表。

 

http://www.cnblogs.com/daniel-D/p/3812795.html

 

分享到:
评论

相关推荐

    Scala函数式编程

     这本书所讲授的,正是基于 Scala 的函数式编程基础。基于 Scheme、Haskell 等老牌函数式语言的传统教材的问题在于,相关语言的语法和思维方式与读者现有的知识体系迥异,容易造成较为陡峭的入门门槛。此外,由于...

    Scala函数式编程.pdf

    函数式编程(FP)是一种...《Scala函数式编程》是针对希望学习FP并将它应用于日常编码中的程序员而写的,内容包括:函数式编程的概念;函数式编程相关的各种“为什么”和“怎么做”;如何编写多核程序;练习和检测。

    函数式编程思维.pdf_函数式编程_函数式编程思维_

    函数式编程有着深厚的理论基础,源于λ演算和函数组合,这使得它在处理复杂逻辑和并行计算时特别有效。 在"函数式编程思维"中,程序员会倾向于用数据流和变换来思考问题,而不是通过控制流程来解决问题。这种方式...

    Scala与Clojure函数式编程

    通过掌握Scala和Clojure中的函数式编程模式,开发者可以更好地利用函数式编程的优势,提高代码质量并降低维护成本。 总之,《Scala与Clojure函数式编程》这本书不仅为OO程序员提供了一条通往FP的路径,也对已经熟悉...

    Scala函数式编程 2016年4月 电子工业出版

    然而,关于“Scala函数式编程”的话题,我可以从一般性知识出发,提供一些基础知识和概念,以满足您的需求。 Scala是一种结合了面向对象编程和函数式编程范式的高级编程语言,适用于处理多核CPU和分布式计算的复杂...

    Scala和Spark大数据分析函数式编程、数据流和机器学习

    Scala是一种静态类型的函数式编程语言,而Spark是一个分布式计算框架,尤其适合于大数据处理和分析。本教程将深入探讨这两者如何结合,实现高效的大数据分析、数据流处理以及机器学习任务。 首先,让我们来理解...

    Scala与Clojure函数式编程模式:Java虚拟机高效编程1

    这本书适合有编程基础,对函数式编程感兴趣的读者,无论你是Java开发者还是对新编程范式好奇的学习者,都可以从中了解到如何在Scala和Clojure中应用函数式编程来提高代码质量和效率。 【结论】 随着大数据时代的...

    functional-programming-in-scala:“Scala 中的函数式编程”练习

    "functional-programming-in-scala"项目中的练习涵盖了以上所述的许多概念,通过实际操作,可以帮助开发者巩固理论知识,提升对Scala函数式编程的掌握。此外,阅读并参与研究组的讨论,可以深入了解其他开发者对这些...

    Scala编程详解 第16讲-Scala编程详解:函数式编程 共14页.pptx

    共13页第15讲-Scala编程详解:面向对象编程之Trait 共14页第16讲-Scala编程详解:函数式编程 共14页第17讲-Scala编程详解:函数式编程之集合操作 共9页第18讲-Scala编程详解:模式匹配 共11页第19讲-Scala编程详解:...

    Scala编程 pdf

    4. **函数式编程**:Scala鼓励使用不可变数据结构和高阶函数,函数是一等公民,可以赋值给变量,作为参数或返回值。λ表达式(匿名函数)和闭包也是重要的概念。 5. **类型推断**:Scala具有强大的类型推断能力,...

    Scala编程详解 第17讲-Scala编程详解:函数式编程之集合操作 共9页.pptx

    共13页第15讲-Scala编程详解:面向对象编程之Trait 共14页第16讲-Scala编程详解:函数式编程 共14页第17讲-Scala编程详解:函数式编程之集合操作 共9页第18讲-Scala编程详解:模式匹配 共11页第19讲-Scala编程详解:...

    快学Scala课后习题答案

    Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的概念。"快学Scala"可能是一个针对初学者的教程或课程,旨在帮助学习者迅速掌握这门语言的基础和高级特性。课后习题是检验学习效果、加深理解的重要...

    函数式编程

    函数式编程是一种编程范式,其核心理念是将计算视为数学函数的...通过学习函数式编程,开发者可以掌握一门编程语言的核心特性,并将这些知识应用到其他强类型函数式语言中,如 Swift、Scala、Haskell 和 PureScript。

    函数式编程工具箱_Scala_JavaScript_下载.zip

    标题中的“函数式编程工具箱_Scala_JavaScript_下载.zip”表明这是一个关于函数式编程的资源包,其中包含了Scala和JavaScript两个编程语言的相关内容。函数式编程是一种编程范式,它强调通过纯函数和避免可变状态来...

    Scala编程实战基础教程

    此外,尾递归优化也是Scala函数式编程的一个亮点,它有助于避免深度递归导致的栈溢出。 Scala还提供了强大的并发模型,基于Actor系统。Actors是独立运行的实体,它们通过消息传递进行通信,这种模型非常适合构建...

    Scala函数式编

    在Scala中,函数式编程是其核心特性之一,它允许开发者以一种声明式而非命令式的方式处理问题,从而提高代码的可读性和可维护性。本文将深入探讨Scala中的函数式编程概念、语法以及其实现方式。 函数作为一等公民 ...

    scala-examples:函数式编程的代码示例

    这个"scala-examples"项目提供了一系列的代码示例,旨在帮助开发者理解如何在实际中运用Scala的函数式编程概念。 首先,让我们深入了解一下Scala的核心概念。Scala的函数式编程允许我们以声明式的方式编写代码,而...

    大数据课程-Scala编程基础-1.Scala语言初识_lk_edit.ppt

    1. 多范式编程:Scala支持面向对象和函数式编程,允许开发者根据需求选择合适的设计模式。 2. 静态类型:Scala是静态类型的,需要在编译时确定类型,以确保代码的稳定性。 3. 可交互性:Scala可以作为脚本语言直接在...

Global site tag (gtag.js) - Google Analytics