monad 学习笔记

作者: Auther丶 | 来源:发表于2016-06-20 09:17 被阅读85次

    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/         
    

    相关文章

      网友评论

        本文标题:monad 学习笔记

        本文链接:https://www.haomeiwen.com/subject/jvdwdttx.html