Lecture 4.1
Functions as Objects
将匿名函数看成一个对象 A=>B 其实就是scala.Function1[A, B]
Function1 是scala系统库的一个Trait,包含一个参数的函数特质
Expansion Function Values
通过 x => x*x 解释这个匿名函数其实也是一个匿名类
new class AnoFun extends Function1[Int, Int]{
apply(x: Int) =x*x
}
Expansion Function Calls
f(a, b) 演变成 f.apply(a,b)
Functions and Methods
方法定义不等同与函数值,方法在使用时才有值,不能将方法定义看做函数值
Lecture 4.2
Polymorphism (多态)
多态基于子类和泛型, 这是Java里面有的。这里引出两个重要概念Bound(类型范围) Variance (类型变异)
bound和子类继承相关,bound和泛型引出variance
S <: T means: S is a subtype of T, and
S >: T means: S is a supertype of T, or T is a subtype of S 注意这个or的描述是一样的,super type 和subtype正好反一下
类型范围举例 [S >: NonEmpty <: IntSet]
S为NonEmpty的父类,但是必须是IntSet的子类
协变举例:
如果说 NonEmpty <: IntSet 那么如果满足 List<NonEmpty> <: List<IntSet> 的话就称为类型协变
我的理解是这个列表或集合中的任意NonEmpty对象都可以安全转换到IntSet对象
里氏替换原则 A <: B 那么如果行为对B的所有行为可以用A替换B后仍旧成立,因为B的抽象层次高,所以B的所有行为都是从A抽象而来
Lecture 4.3
Pure Object Orientation
举例说明scala纯面向对象的,如何将primitive 类型转化成一个Class
Pure Boollean
关键点在于理解 def ifThenElse [T](t: => T, e: => T): T
还是回到函数就是类,类就是函数的思想上来,所有的类都是可以看成函数的,所以Scala如果是纯函数式语言,那么它也是纯面向对象语言。
把Boolean 对象看做一个递归函数,
if (cond) te
else ee
cond.ifThenElse(te, ee)
如果 false < true 为boolean实现一个 < 的函数实现
<(x:Boolean) ifThenElse( false, x)
如何实现一个自然数,只能用对象和函数不能使用基本类型
abstract class Nat {
def isZero: Boolean
def predecessor: Nat
def successor: Nat
def + (that: Nat): Nat
def - (that: Nat): Nat
}
object Zero extends Nat
class Succ(n: Nat) extends Nat
将一切看成对象,忘记 0, 1,2, 3, 4 这里理解的关键是把自然数看成是一个一个的对象
自然数在这里看做下面的数列
Zero, Succ(Zero), Succ(Succ(Zero)), Succ(Succ(Succ(Zero)))), …
Lecture 4.4 Variance (型变)(老师一开始就说这部分较难,可以略过或只是看看就行)不管对不对,先做些记录吧
型变的定义分三类,在scala中定义如下:
Covariant 协变 class C[+A] { ... }
Contravariant 逆变 class C[-A] { ... }
Nonvariant (不知道怎么翻译) class C[A] { … }
练习思考,假设
type A = IntSet => NonEmpty
type B = NonEmpty => IntSet
那么 A和B的关系是?
老师对为什么做了详细解释,使用里氏替换原则。
继续巩固大家的思想,函数即类型,类型即函数的概念。推导出以下公式
如果 A2 <: A1 , B1 <: B2 那么如下函数存在如下型变关系
A1 => B1 <: A2 => B2
Function Trait Declaration
下面引出scala里面认为函数即类型,类型即函数的重要特质 Function1的定义
package scala
trait Function1[-T, +U] {
def apply(x: T): U
}
Variance check (型变检查)
Scala的大致性规则
- 协变一般出现在函数返回类型上
- 逆变一般出现在函数的参数类型上
- 不型变可以出现在任何地方
通过List的例子来说明怎样扩大类型定义时的类型来适应函数返回值的多样类型,Scala居然可以让函数返回自适应类型?对,这是为模式匹配做铺垫啊。
trait List[+T] { ... }
object Empty extends List[Nothing] { ... }
将List返回类型定义为[T+] 来适应NoEmpty 和Empty 两种可能的返回值, 看起来太酷了。
再通过List的一个函数prepend举例说明,当函数返回值和参数如何通过使用协变通过scala编译
返回值 U :> T, T类型为参数类型, 通过这种方式放大返回值的类型范围。
这里看的似懂非懂,但记住一点真理,scala里面的函数就是类型,类型就是函数
def prepend [U >: T] (elem: U): List[U] = new Cons(elem, this)
def f(xs: List[NonEmpty], x: Empty) = xs prepend x ?
xs prepend x = new Cons(x, xs) 返回了List <Empty> 所以xs prepend x 的类型为 List<IntSet>
思考:型变好厉害,怎么瞧着和匿名函数有点关系呢? 函数对参数进行运算后发生类型变换,函数即类型,类型即函数才让型变成为可能?
本文出自 “刀客” 博客,转载请与作者联系!
原文地址:http://kris21.blog.51cto.com/9243389/1613860