functor (实现了map的数据类型) & monad (实现了flatMap的数据类型)
就以optional 的map 和 flatMap 来说
public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U? 简化下 map:(f(x)) ->U?
public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U? 简化下 flatMap:(f(x)) ->U?
这样看是一样的,但是看f(x),map 中的f(x) 是返回一个U flatMap的f(x)是返回一个U?
再看map 和flatMap 的最终返回值 都是U? Optional(U) 类型的,也就是map 拿到f(x)的之后,封装Optional类型再返回,而flatMap直接就是返回f(x)计算出来的Optional类型。
举个例子
map:{ x:int -> int in x * 2 } 其中这一块 { x:int -> int in x * 2 } 看成y = f(x) 这个表达式是传入x,传出x*2.
然后根据以下map的源码 可以看到 map将计算出来的值2x包上了一个Optional.Some(2x)
它就变成了Optional<Int>.some . map 这样做的的意义更多是为了链式调用
/// If `self == nil`, returns `nil`.
/// Otherwise, returns `f(self!)`.
public func map<U>(@noescape f: (Wrapped) throws -> U)
rethrows -> U? {
switch self {
case .Some(let y):
return .Some(try f(y))
case .None:
return .None
}
}
再看下flatMap的传参 f(x) = {x:Int -> Int? in x * 2 } 注:大家都知道,是可以将Int类型的值赋值给Int?类型的,反过不行,看optional的构造函数就行。
然后看下flatMap拿到f(x)的实现,是直接返回了f(x)的计算结果
@warn_unused_result
public func flatMap<U>(@noescape f: (Wrapped) throws -> U?)
rethrows -> U? {
switch self {
case .Some(let y):
return try f(y)
case .None:
return .None
}
}
好了 现在咱们假设有个closure f(x),这个f(x) 有可能会return nil,也就是会返回optional.None 例如这样
可以看出来这个是吻合 flatMap的f的。接受Int 返回 Int? Int的封装。 但是如果你把它传给了map 也不会报错,但是有潜在的问题。
f(x) = { (a: Int) -> Int? in
if a % 2 == 0 {
return a
} else {
return nil
}
潜在的问题:
let tq: Int? = 1
let b = tq.map { (a: Int) -> Int? in
if a % 2 == 0 {
return a
} else {
return nil
}
}
//b为 Some<None> Optional(Optional(nil)) 这样第一次拆开盒子,发现里面不是空,而是另一个盒子c。只有把盒子c拆开才发现是空
if let c = b {
print("not nil") //不会打印not nil
}
可以看到,map的参数 f(x) 的计算结果不希望是盒子类型(类似Optional),这个f(x)很单纯,你传进来x :Int 计算后 给你一个y:Int
如果上面的tq.map 换成 tq.flatMap{} 那就完美的符合了flatMap 的胃口,他就想要传进来的closure 是这样的:传一个值,返回一个盒子。
Functor 的函数定义是从「未封装的值」到「未封装的值」
Monad 的函数定义是从「未封装的值」到「封装后的值」
再啰嗦一遍,不管是Optional的 map 还是 flatMap 最终返回结果都必然是 Optional类型。
为了达到这个目的,map呢, 一直认为他的f(x)的计算结果是一个确切的值,例如 1 ,2 3,或者optional.None . 所以他就得将f(x)的结果放进一个盒子里,即封装成Optional。
flatmap呢,就简答了,他认为自己的f(x) 的计算结果就已经是一个Optional值--封装过得值了.当然你也可以这样写,最终得到仍然是一个Optional类型的值.这个还是归功于最后的 U?如果最终返回的不是一个Optional类型的,就会构造成一个Optional类型的。如果你改成str -> String??? 那么就会返回 String???类型
map 返回的永远比你f(x)里面写的多一层optional,而flatMap最终得到的最少是一层Optional。
let g = f.flatMap { str -> String in
return str // str 为Swift.String
}//g 为 Swift.Optional<Swift.String>
这样是为了更好的链式调用。不要被return前面的值所迷惑。
学习 唐巧和雷纯峰 所分享的 Monad
http://blog.leichunfeng.com/blog/2015/11/08/functor-applicative-and-monad/
http://blog.devtang.com/2016/03/05/swift-gym-4-map-and-flatmap/
网友评论