ReactiveCocoa------Functor、Applicatives和Monad

引言

计算机科学习惯于为抽象概念命名术语,我们也从这些术语中获益良多。这些术语使我们在交流中能够引用抽象概念,并立即使对方知道我们的意思,比如我们从设计模式的共享名称(工厂、装饰器等)中获益良多。其中一些术语非常抽象,如:函数式编程中的Functor、Applicatives和Monad。

Functor、Applicatives和Monad的概念源自范畴论。本篇笔者从Swift的Optional入手阐述Functor、Applicatives和Monad在函数式编程中的概念。对比于OC,swift提供了对函数式编程更好的支持。

Optional

Apple在WWDC 2014开发者大会上发布了用于Mac OS X和iOS编程的新一代编程语言Swift。Optional(可选值)为Swift中一个重要的概念。

Optional-封装后的值

Optional数据类型事实上就是封装后的值,即对值及其上下文环境进行封装的结果。

Optional的定义:

1
2
3
4
5

public enum Optional<Wrapped> {
case none
case some(Wrapped)
}

一个Optional类型的值,为空的时候就是.none,不为空的时候就是.some。当我们将一个函数应用于Optional,不同上下文(.some或.none)我们将得到不同的结果。函数式编程中Functor、Applicatives和Monad的概念就是基于对封装后的值进行操作。

函数式编程中将值与上下文进行封装,对封装后的值进行操作可以集中于我们想要完成的事情,省去了异常分支(.none)的判断、嵌套。这样的代码具有更高的可读性,也更不易出错。如在RAC中对RACSignal发送的map、filter操作的过程中,我们将精力集中在next事件上,error、completed事件的传递处理都封装在RACSignal中。

MyOptional

Swift的Optional只满足函数式编程中的Functor,Monad,并不满足Applicatives的概念。笔者在ReactiveCocoa高阶操作中给出了Functor、Applicatives和Monad概念定义。本篇中笔者用Swift实现满足Functor、Applicatives和Monad概念的MyOptional对这些概念进一步阐述。

MyOptional定义

类似Optional 给出简单定义

1
2
3
4
enum MyOperation <T> {
case some(T)
case none
}

我们可以将Functor、Applicatives和Monad理解为一种协议,遵循该协议实现对应的方法,即为满足Functor、Applicatives和Monad。

Functor

Functor:应用一个函数到封装后的对象。

添加map函数,应用函数到MyOptional对象,使MyOptional满足Functor。

map实现

1
2
3
4
5
6
7
8
9
10
11
12
extension MyOptional{
//应用一个函数到MyOptional
func map<U>(f: (T) -> U) -> MyOptional<U> {
switch self {
case let .some(a):
return MyOptional<U>.some(f(a))

case .none:
return MyOptional<U>.none
}
}
}

map使用

通过map方法,应用plusTree到MyOptional对象,同时在plusTree中我们只关注想要执行的操作,.none的异常分支被封装在MyOptional的map实现中。

1
2
3
4
5
6
7
8
9
func plusTree(addend:Int) -> Int {
return addend + 3
}

let some = MyOptional.some(2).map(f: plusTree)
let none = MyOptional<Int>.none.map(f: plusTree)

print(some)// output some(5)
print(none)// output none

Applicatives

Applicatives:应用一个封装后的方法到一个封装后的对象。

函数式编程中函数是一等公民,我们可以将值与其上下文进行封装,同样我们也可以将函数与其上下文进行封装。

添加apply函数,应用函数到MyOptional对象,使MyOptional满足Applicatives。

apply实现

1
2
3
4
5
6
7
8
9
10
11
12

extension MyOperation{
//应用一个封装过的函数到MyOperation
func apply<U>(f:(MyOperation<(T)->U>))-> MyOperation<U> {
switch f {
case let .some(someF):
return self.map(f: someF)
case .none:
return .none
}
}
}

apply使用

1
2
3
4
5
6
7
8
9
10
11
12
func plusTree(addend:Int) -> Int {
return addend + 3
}

let funcSome = MyOptional.some(plusTree)
let funcNone = MyOptional<(Int)->Int>.none

let some = MyOptional.some(2).apply(f: funcSome)
let none = MyOptional.some(2).apply(f: funcNone)

print(some)// output some(5)
print(none)// output none

将plusTree和 MyOptional<(Int)->Int>.none封装为MyOption,并通过apply进行调用。

Monad

Monad:应用一个返回封装后的对象的方法到一个封装后的对象。

添加flatMap函数,应用一个返回封装后的对象的函数到一个封装后的对象。使MyOptional满足Monad。

flatMap实现

1
2
3
4
5
6
7
8
9
10
11
12
extension MyOptional{

//应用一个返回MyOptional的函数到MyOptional
func flatMap<U>(f: (T) -> MyOptional<U>) -> MyOptional<U> {
switch self {
case let .some(a):
return f(a)
case .none:
return .none
}
}
}

flatMap使用

1
2
3
4
5
6
7
8
9
10
//返回MyOptional的函数
func plusTree(addend:Int) -> MyOptional <Int> {
return MyOptional<Int>.some(addend + 3)
}

let some = MyOptional.some(2).flatMap(f: plusTree)
let none = MyOptional<Int>.none.flatMap(f: plusTree)

print(some)// output some(5)
print(none)// output none

至此,通过添加map、apply、flatMap函数,MyOptional分别“遵循Functor、Applicative、Monad协议”。我们可以称MyOptional是Functor/Applicative/Monad。

结论

  • 一个 Functor 就是一种实现了 Functor typeclass(协议) 的数据类型;
  • 一个 Applicative 就是一种实现了 Applicative typeclass(协议) 的数据类型;
  • 一个 Monad 就是一种实现了 Monad typeclass(协议)的数据类型。

相关链接

Swift Functors, Applicatives, and Monads in Pictures
Functors, Applicative Functors and Monoids