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 学习笔记

    functor (实现了map的数据类型) & monad (实现了flatMap的数据类型) 就以optiona...

  • 函数式内功心法-00: 万物互连之monad创世纪

    很多人学习haskell,都会在monad这个概念上迷失。真是天下苦monad久矣! 人们常常说 Monad不就是...

  • Haskell学习-monad

    原文地址:Haskell学习-monad 什么是Monad Haskell是一门纯函数式的语言,纯函数的优点是安全...

  • 函数式编程下的visitor模式

    在深入理解函数式编程之monad中,我们详细讲述了monad模式,以及monad模式和functor模式之间的区别...

  • Monad 定律

    monad 是支持>>=操作的 applicative 函子,>>=读作绑定,它的类型是: 即取一个 monad ...

  • Reader Monad

    本文使用Haskell语言,并需要读者有Monad的基本概念 什么是Reader Monad 在介绍Reader之...

  • 【函数式】Monads模式初探——Option Monad

    Option Monad Scala中的Option是一个Monad实现。Option的简化版定义如下: 代码中,...

  • 理解范畴论中单子需要的最小知识集

    A monad is just a monoid in the category of endofunctors,...

  • monad

    函子:对map函数的泛化在第一部分和第二部分实现了一些不同组合子库。这些组合子的相似性是值得注意的,比如为每个数据...

  • Monad

    Monad不就是个自函子范畴上的幺半群,这有什么难理解的(A monad is just a monoid in ...

网友评论

    本文标题:monad 学习笔记

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