Scala By Example: 一等公民

本文介绍Scala中的匿名函数与Currying方法的应用,并提供基于定点法的函数实例,包括开方等数学运算。此外,还提供了多个针对Scala函数式编程的练习题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

匿名函数
   1: def sum(f: Int => Int, a: Int, b: Int): Int =
   2:   if(a > b) 0 else f(a) + sum(f, a + 1, b)
   3:  
   4: def sumSquares(a: Int, b: Int): Int =
   5:   sum((x: Int) => x * x, a, b)

在这个最基本的示例中,sum 接受了一个函数 f 作为参数。这里,sum 就是一个 higher-order 函数。而在 sumSquares 中,我们传入了另外一个匿名函数 (x: Int) => x * x 作为 sum 的参数。注意,由于在 sumSquares 中 a “必定”是 Int 类型,因此编译器将可以推断出传入 sum 的函数的参数类型,所以传入的函数可以略去类别声明。同时,当传入的函数只有一个参数且类型被省略的时候,括号也是可选的。也就是说,上例可以简化为:

   1: def sumSquares(a: Int, b: Int): Int = sum(x => x * x, a, b)

事实上,匿名函数并不是 Scala 的核心语法,它总是会被扩展成一个具名的函数,所以,可以把匿名函数视作一个语法糖。

Currying

虽然通过传递函数作为参数能够极大的简化代码,但是在上例中,两个函数都包含了同样的 a 和 b 两个参数,通过 Currying 方法还可以进一步简化。假设函数 f 定义为:f(args1)...(argsn) = E 其中 args1 到 n 为一连串的参数列表,每次展开都会返回一个函数,则该函数可以展开为:f(args1)...(argsn-1) = (argsn) => E。不断重复该过程,则可以得到:f = (args1) =>...=>(argsn) => E。这种风格也就是所谓的 Currying (提出者 Haskell B. Curry)。通过 Curry 化,代码重写如下:

   1: def sum(f: Int => Int)(a: Int, b: Int): Int =
   2:     if(a > b) 0 else f(a) + sum(f)(a + 1, b)
   3:  
   4: def sumSquares = sum(x => x * x) _

原书的代码是从另外一个不同结构的代码演进过来的,因此并没有提到如何调用最终版本的 sum 函数。注意第四行结尾的下划线,它标记出了一个部分实现函数。

注:铅笔书上6.4节介绍了 Currying 的语法,但没有说原理,Example 则讲了原理,语法被一笔带过了。

练习1:将 sum 改写成尾递归

练习2:把 sum 的逻辑从加法改成乘法,写成新的函数 product

练习3:通过 product 来实现阶乘

练习4:把 sum 和 product 写成一个函数

范例:定点法函数 fixed-point finding function

Fixed-Point 定义 (我觉得铅笔书更注重语法,而Example有点像初级算法书,更注重表达函数式编程的"风味",所以……学点数学吧)

   1: val tolerance = 0.0001
   2: def isCloseEnough(x: Double, y: Double) = scala.math.abs((x - y) / x) < tolerance
   3: def fixedPoint(f: Double => Double)(firstGuess: Double) = {
   4:   def iterate(guess: Double): Double = {
   5:     val next = f(guess)
   6:     if(isCloseEnough(guess, next)) next
   7:     else iterate(next)
   8:   }
   9:   iterate(firstGuess)
  10: }
  11:  
  12: // made the iteration converge by averaging successive values, this technique
  13: // of average damping is so general that it can be wrapped in another function
  14: def averageDamp(f: Double => Double)(x: Double) = (x + f(x)) / 2
  15:  
  16: def sqrt(x: Double) = fixedPoint(averageDamp(y => x / y))(1.0)

以上就是一个定点法函数及以此为基础的开方函数,注意第二行的 scala.math.abs,在“很久以前”Scala 有个 Math 对象来处理数学运算,但既然可以把 value 放在 package 下,那么为什么不用更具备 Scala 风格的方式呢?还有,记得在第四章曾经有个习题是关于开方函数的精度问题的,当时我的答案是 x - y < x * tolerance 这样的逻辑,虽然说在实际应用中,你不会遇到 x 为 0 的问题,但是即使只是为了保持警觉,采用我的逻辑也是值得的。另外值得注意的就是 average damping 方法,使用平均值衰减的方法可以保证你的函数逐步收敛到一个定点数,而不是因为改变太大而发散导致死循环。

练习5:写一个开立方根的函数

Technorati 标签: Scala
1 Introduction 1 2 A First Example 3 3 Programming with Actors and Messages 7 4 Expressions and Simple Functions 11 4.1 Expressions And Simple Functions . . . . . . . . . . . . . . . . . . . . . . 11 4.2 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 4.3 Conditional Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4.4 Example: Square Roots by Newton’s Method . . . . . . . . . . . . . . . . 15 4.5 Nested Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 4.6 Tail Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 5 First-Class Functions 21 5.1 Anonymous Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.2 Currying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 5.3 Example: Finding Fixed Points of Functions . . . . . . . . . . . . . . . . 25 5.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 5.5 Language Elements Seen So Far . . . . . . . . . . . . . . . . . . . . . . . 28 6 Classes and Objects 31 7 Case Classes and Pattern Matching 43 7.1 Case Classes and Case Objects . . . . . . . . . . . . . . . . . . . . . . . . 46 7.2 Pattern Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 8 Generic Types and Methods 51 8.1 Type Parameter Bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 8.2 Variance Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56iv CONTENTS 8.3 Lower Bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 8.4 Least Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 8.5 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 8.6 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 9 Lists 63 9.1 Using Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 9.2 Definition of class List I: First Order Methods . . . . . . . . . . . . . . . 65 9.3 Example: Merge sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 9.4 Definition of class List II: Higher-Order Methods . . . . . . . . . . . . . 70 9.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 10 For-Comprehensions 79 10.1 The N-Queens Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 10.2 Querying with For-Comprehensions . . . . . . . . . . . . . . . . . . . . . 81 10.3 Translation of For-Comprehensions . . . . . . . . . . . . . . . . . . . . . 82 10.4 For-Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 10.5 Generalizing For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 11 Mutable State 87 11.1 Stateful Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 11.2 Imperative Control Structures . . . . . . . . . . . . . . . . . . . . . . . . . 91 11.3 Extended Example: Discrete Event Simulation . . . . . . . . . . . . . . . 92 11.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 12 Computing with Streams 99 13 Iterators 103 13.1 Iterator Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 13.2 Constructing Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 13.3 Using Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值