Scala函数式程序设计原理 week1 Getting Started + Functions & Evaluation
求值策略
两种策略
Scala中有两种求值策略,一种叫做calll by name一种叫做call by value。两种策略会规约成相同的最终值,只要满足
- 规约表达式由纯函数组成
- 两者求值过程能够终止(不存在无限循环)
终止性质
当不满足终止条件时
- 如果CBV能够终止,那么CBN也能够终止
- 反之不成立
Scala中通常使用call-by-name,如果函数参数的类型以=>
开头,则表明使用call-by-name。
def constOne(x:Int,y:Int => Int) = 1
条件表达式
Scala中的if-else
是表达式,由有值。每个表达式都有一个类型,表达式的类型是两个公共分支的超类型。
如果else部分缺失了,
if (x>0) 1
那么可能if语句没有输出值,解决办法是引入一个Unit
类,写作()
。等同于
if (x>0) 1 else ()
可以把()当作”无有用值”的占位符,将Unit当作void。(从技术上讲void没有值但是Unit有一个表示”无值”的值)
声明值和变量
val
被定义时即被取值
lazy val
在首次使用时取值
def
在每一次被使用时取值
返回值类型
递归函数需要显式地指明返回值的类型,非递归函数的返回值类型是可选的。
块表达式
{}
块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
在Scala中,赋值动作本身是没有值得,严格地说他们得值是Unit
类型的,写作()
。
由于赋值语句的值是Unit
类型,不要把他们串联在一起。
x = y = 1 //别这样做
可见性
块表达式内部的定义只能内部可见。内部的定义会遮蔽外部的同名定义。
分号和中缀运算符
Scala中,行尾的分号是可选的。
一行中有多个语句,每个语句用分号分隔。
当要多行表达式的时候,可以卸载括号内。
(someLongExp +somOtherExp)
或者可以在第一行写操作符,因为这告诉编译器表达式还未结束
someLongExp +
someOtherExp
尾递归
如果一个函数在最后一步操作中调用自身,那么函数调用栈空间可以被重复使用。这叫做尾递归。
尾递归是迭代过程
在Scala中,只有直接递归调用自身是可以被优化的。
使用@tailrec
注解可以要求函数是尾巴递归的
@tailrec
def gcd(a: Int,b: Int): Int = ...
如果gcd的实现不是尾递归的,会报错。
参考资料
Scala函数式程序设计原理 week1
《快学Scala 第一版》