Monad学习
这是观看Cousera上的课程《Principles of Reactive Programming》中week1里的Monad一节所做的笔记。
What is a Monad?
What is a Monad?
A monad is a parametric type M[T] with two operations, flatMap and unit, that have to satisfy some laws.
这里是说Monad是一类特殊的类型,它有两个方法, flatMap和unit,这两个方法必须满足一些约束。嗯……并不是说任何有flatMap和unit方法的类都是Monad, Monad的这两个方法是有特定语义的,也正是这两个方法的语义使一个类型成为Monad.
用Scala来定义Monad如下:
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]
如果Monad被定义为一个trait,那么unit方法并不是这个trait的一部分,而是独立于Monad对象的。我觉得,可以理解为unit是一个生成Monad对象的方法,它和具体的对象没有关系。
Examples of Monads
- List is a monad with unit(x) = List(x)
- Set is a monad with unit(x) = Set(x)
- Option is a monad with unit(x) = Some(x)
- Generator is a monad with unix(x) = single(x) 注:Generator是Cousera的这门课程里的上一小节里讲到的一个类
flatMap is an operation on each of these types, whereas unit in Scala is different for each Monad.
实际上,List Set Option和Generator都可以看成集合,从这些集合的unit方法的定义可以看出,unit就是简单的对一个元素进行包装,使其成为一个类似于“单元素集合”的东西。
Monad and map
map can be defined for every monad as a combination of flatMap and unit:
m map f == m flatMap (x => unit(f(x)))
== m flatMap( f andThen unit)
实际上map的这种定义已经限制了flatMap和unit的语义。
m map f, 对于上边提到的Monad的语义都是把m中的每个元素通过f映射为另一个monad中的一个元素。因此,若想m map f == m flatMap( x => unit(f(x))), unit和语义和flatMap的语义就得配合起来。也就是说,对于f(x),经过unit的处理,再经过flatMap的处理,还是f(x).
因此定义flatMap的重点在于如何把一组Monad组合成一个Monad。对于List,这个组合方法就是 ++, 对于Generator,就是
def flatMap[S](f: T => Generator[S]): Generator[S] = new Generator[S]{
def generate = f(self.generate).generate
}
即将每个元素运用f,生成一组Monad, 然后取这一组Monad中每个Monad的第一个元素组成一个Monad.
假如,我们定义一种Monad: 一串山楂。 0000
定义unit为:把一个山楂 0 拿一个竹签串起来,让它成为”一串山楂“。 0
定义g为把一个山楂变为一串山楂,具体怎么变由g的定义决定。 可见unit函数是g函数的一种。
定义flatMap(g)为把此山楂串的每个山楂应用g,得到很多串山楂,然后把这些山楂串 串成一整个山楂串。
定义函数f为把每个山楂包上糖。即从 0 变成 @
由以上定义可以推出:
m map f就是把m里的每个山楂都包上糖,再把这些山楂直接串起来,变成 @@@@
那么 x => unit(f(x))就是把一串山楂里的每一个0拿出来,先包上糖变成@,然后用一个竹签把这一个糖山楂串起来。 @
那么flatMap(x => unit(f(x)))就是就是把每个山楂应用 x => unit(f(x)),形成很多只有一个山楂的山楂串 @ @ @ @ , 然后把它们串到一起,变成 @@@@ , 也就等于 m map f
在以上的定义下 m map f == m flatMap(x => unit(f(x)))
Monad Laws
To qualify a monad, a type has to satisfy three laws:
Associativity:
m flatMap f flatMap g == m flatMap( x => f(x) flatMap g)
Left unit
unit(x) flatMap f == f(x)
Right Unit
m flatMap unit == m
这个结合律理解起来有点困难,得先回忆一下flatMap的定义
def flatMap[U](f: T => M[U]): M[U]
这里重点留意下定义里跟数据类型有关的部分。
f: T => M[U] 因此,f是一种Monad的生成器。如果把f用于map,即 m map f, 结果的类型会是M[M[U]],但是m flatMap f, 结果是M[U]。这就是flatMap神奇的地方,m flatMap f得到的值的类型跟m的类型是一样的(都是Monad)。比如,我们定义Int类型有个方法是^2,是求平方,那么就可以 3 ^2 ^2 ^2这样一直算下去,这样就可以很方便地利用递归。比如^6就可以在递归中用^2算出来。因此flatMap的这种对类型的保持,使得可以对Monad做无限的的flatMap,仍然得到Monad。也就是使得所有对Monad的操作都适用于m flatMap f。
也就是说我们可以m flatMap f flatMap g,也可以m flatMap f flatMap g flatMap k这样一直进行下去。
那么
Associativity:
m flatMap f flatMap g == m flatMap( x => f(x) flatMap g)
的意义何在?
Associativity says essentially that one can "inline" nested for expressions:
for(y <- for (x <-m; y <- f(x))yield y
z <- g(y)) yield z
== for{ x <- m
y <- f(x)
z <- g(y)
} yield z
来证明一下:
for( y <- for( x <- m; y <- f(x)) yield y
z <- g(y)) yield z
令 k = for(x <-m; y <- f(x)) yield y
原式变成for{y <- k
z <- g(y)} yield z
== k flatMap (y => for( z <- g(y) yield z)
== k flatMap ( y => (g(y) map ( z => z)))
== k flatMap ( y => g(y))
== k flatMap g
而 k = for{x <- m; y <- f(x)} yield y
= m flatMap ( x => (for( y <- f(x) yield y))
= m flatMap ( x => f(x))
= m flatMap f
所以
for( y <- for( x <- m; y <- f(x)) yield y
z <- g(y)) yield z
== m flatMap f flatMap g
而
for{ x <- m
y <- f(x)
z <- g(y)
} yield z
== m flatMap (x => (for (y <- f(x); z <- g(y)) yield z)
== m flatMap (x => f(x) flatMap( y => g(y))
== m flatMap (x => f(x) flatMap g)
所以,这两个for循环相等,要求 m flatMap f flatMap g == m flatMap(x => f(x) flatMap g), 也就是要求结合律成立。
从另一个角度看这回事,m flatMap f flatMap g就是连续做了两次flatMap。 而 f flatMap(x => f(x) flatMap g),令k = (x => f(x) flatMap g)), 即m flatMap f flatMap g == f flatMap k, 即我们可以用 x => f(x) flatMap g 构造一个新的函数k,使得 m flatMap f flatMap g == f flatMap g。
Monad学习的更多相关文章
- Haskell学习-monad
原文地址:Haskell学习-monad 什么是Monad Haskell是一门纯函数式的语言,纯函数的优点是安全可靠.函数输出完全取决于输入,不存在任何隐式依赖,它的存在如同数学公式般完美无缺.可是 ...
- Haskell语言学习笔记(72)Free Monad
安装 free 包 $ cabal install free Installed free-5.0.2 Free Monad data Free f a = Pure a | Free (f (Fre ...
- 泛函编程(27)-泛函编程模式-Monad Transformer
经过了一段时间的学习,我们了解了一系列泛函数据类型.我们知道,在所有编程语言中,数据类型是支持软件编程的基础.同样,泛函数据类型Foldable,Monoid,Functor,Applicative, ...
- ReactiveCocoa学习总结
最近一直断断续续学习关于ReactiveCocoa的知识内容,对于它的一些基础内容将通过本文进行一个总结,主要是一些入门知识 一:RACSignal一些运用 @interface RACSignalT ...
- 转评:你造promise就是monad吗
看到一遍好文章,与我的想法如出一辙,先转为敬.首先说说我对Monad和promise的理解: Monad的这种抽象方式是为了简化程序中不确定状态的判断而提出的,能够让程序员从更高的层次顺序描述程序逻辑 ...
- Monad / Functor / Applicative 浅析
前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...
- 一个Monad的不严谨介绍
一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已,这有什么难以理解的?* 之前了解了下Monad,后来一段时间没碰,最近研究Parser用到Monad时发现又不懂了.现在重新折腾,趁着 ...
- 翻译连载 | 附录 B: 谦虚的 Monad-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- Haskell学习-函数式编程初探
原文地址:Haskell学习-函数式编程初探 为什么要学习函数式编程?为什么要学习Haskell? .net到前端,C#和JavaScript对我来说如果谈不上精通,最起码也算是到了非常熟悉的 ...
随机推荐
- 每天一道LeetCode--342. Power of Four
Given an integer (signed 32 bits), write a function to check whether it is a power of 4. Example:Giv ...
- mysql 打包表在phpmyadmin提示正在使用中..
一,利用phpmyadmin修改表功能,REPAIR TABLE `你的表名` 或直接在数据库管理界面,选中表如下图 二,如果利用修改功能失败了我们还可以尝试在替换本地mysql数据库时,我们先停止m ...
- Redis rdb文件CRC64校验算法 Java实现
查看RDB文件结构,发现最后的8字节是CRC64校验算得,从文件头开始直到8字节校验码前的FF结束码(含),经过CRC64校验计算发现,貌似最后的8字节是小端模式实现的. 参考redis的crc64实 ...
- MD5和Base64介绍与应用
MD5:概念:MD5是一种不可逆的消息摘要算法.为计算机安全领域广泛使⽤的一种散列函数, 用以提供消息的完整性保护.效果:把一个任意长度的字节串变换成⼀定⻓度的⼗六进制数字串. 目的是让⼤容量信息在⽤ ...
- out ref区别
1.使用ref型参数时,传入的参数必须先被初始化.对out而言,必须在方法中对其完成初始化. 2.out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候. ...
- Using LINQ Group By and String.Join() / Aggregate() in Entity Framework 3.5
linq to sql 的时候,有时候需要用到 先group 然后来个 aggregate 串连一下值, 但会总会出错,说不识别 aggregate 或者 string.join 方法 搜遍网络 一 ...
- 通过Curator操作Zookeeper的简单例子代码
Curator主要解决了三类问题: 一个是ZooKeeper client与ZooKeeper server之间的连接处理; 一个是提供了一套Fluent风格的操作API; 一个是ZooKeeper各 ...
- <%@include和<jsp:include
博客地址:http://www.cnblogs.com/shizhongtao/p/3506742.html欢迎交流 <%@ include %>是编译时包含,<jsp:includ ...
- Codevs 1158 尼克的任务
1158 尼克的任务 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮 ...
- IIS安装Web Deploy之后没有显示右键菜单
Bug描述: 使用IIS自带的"Web平台安装程序"安装完Web Deploy组件之后,鼠标右键点击网站,弹出的菜单中并没有新增的"部署"选项. Bug解决: ...