[Functional Programming] Monad
Before we introduce what is Monad, first let's recap what is a pointed functor:
A pointed functor is a Functor with .of() method
Why pointed Functor is imporant? here
OK, now, let's continue to see some code:
const mmo = Maybe.of(Maybe.of('nunchucks'));
// Maybe(Maybe('nunchucks'))
We don't really want nested Functor, it is hard for us to work with, we need to remember how deep is the nested Functor.
To solve the problem we can have a new method, call '.join()'.
mmo.join();
// Maybe('nunchucks')
What '.join()' does is just simply reduce one level Functor.
So how does implememation of 'join()' looks like?
Maybe.prototype.join = function join() {
return this.isNothing() ? Maybe.of(null) : this.$value;
};
As you can see, we just return 'this.$value', instead of put the value into Maybe again.
With those in mind, let's define what is Monad!
Monads are pointed functors that can flatten
Let's see a example, how to use join:
// join :: Monad m => m (m a) -> m a
const join = mma => mma.join(); // firstAddressStreet :: User -> Maybe Street
const firstAddressStreet = compose(
join,
map(safeProp('street')),
join,
map(safeHead), safeProp('addresses'),
); firstAddressStreet({
addresses: [{ street: { name: 'Mulburry', number: }, postcode: 'WC2N' }],
});
// Maybe({name: 'Mulburry', number: 8402})
For now, each map opreation which return a nested map, return call 'join' after.
Let's abstract this into a function called chain.
// chain :: Monad m => (a -> m b) -> m a -> m b
const chain = curry((f, m) => m.map(f).join()); // or // chain :: Monad m => (a -> m b) -> m a -> m b
const chain = f => compose(join, map(f));
Now we can rewrite the previous example which .chain():
// map/join
const firstAddressStreet = compose(
join,
map(safeProp('street')),
join,
map(safeHead),
safeProp('addresses'),
); // chain
const firstAddressStreet = compose(
chain(safeProp('street')),
chain(safeHead),
safeProp('addresses'),
);
To get a feelings about chain, we give few more examples:
// getJSON :: Url -> Params -> Task JSON
getJSON('/authenticate', { username: 'stale', password: 'crackers' })
.chain(user => getJSON('/friends', { user_id: user.id }));
// Task([{name: 'Seimith', id: 14}, {name: 'Ric', id: 39}]); // querySelector :: Selector -> IO DOM
querySelector('input.username')
.chain(({ value: uname }) => querySelector('input.email')
.chain(({ value: email }) => IO.of(`Welcome ${uname} prepare for spam at ${email}`)));
// IO('Welcome Olivia prepare for spam at olivia@tremorcontrol.net'); Maybe.of()
.chain(three => Maybe.of().map(add(three)));
// Maybe(5); Maybe.of(null)
.chain(safeProp('address'))
.chain(safeProp('street'));
// Maybe(null);
Theory
The first law we'll look at is associativity, but perhaps not in the way you're used to it.
// associativity
compose(join, map(join)) === compose(join, join);
These laws get at the nested nature of monads so associativity focuses on joining the inner or outer types first to achieve the same result. A picture might be more instructive:

The second law is similar:
// identity for all (M a)
compose(join, of) === compose(join, map(of)) === id;
It states that, for any monad M, of and join amounts to id. We can also map(of) and attack it from the inside out. We call this "triangle identity" because it makes such a shape when visualized:

Now, I've seen these laws, identity and associativity, somewhere before... Hold on, I'm thinking...Yes of course! They are the laws for a category. But that would mean we need a composition function to complete the definition. Behold:
const mcompose = (f, g) => compose(chain(f), g); // left identity
mcompose(M, f) === f; // right identity
mcompose(f, M) === f; // associativity
mcompose(mcompose(f, g), h) === mcompose(f, mcompose(g, h));
They are the category laws after all. Monads form a category called the "Kleisli category" where all objects are monads and morphisms are chained functions. I don't mean to taunt you with bits and bobs of category theory without much explanation of how the jigsaw fits together. The intention is to scratch the surface enough to show the relevance and spark some interest while focusing on the practical properties we can use each day.
[Functional Programming] Monad的更多相关文章
- [Functional Programming Monad] Refactor Stateful Code To Use A State Monad
When we start to accumulate functions that all work on a given datatype, we end up creating a bunch ...
- [Functional Programming Monad] Apply Stateful Computations To Functions (.ap, .liftA2)
When building our stateful computations, there will come a time when we’ll need to combine two or mo ...
- [Functional Programming Monad] Combine Stateful Computations Using Composition
We explore a means to represent the combination of our stateful computations using familiar composit ...
- [Functional Programming Monad] Combine Stateful Computations Using A State Monad
The true power of the State ADT really shows when we start combining our discrete, stateful transact ...
- [Functional Programming Monad] Modify The State Of A State Monad
Using put to update our state for a given state transaction can make it difficult to modify a given ...
- [Functional Programming Monad] Substitute State Using Functions With A State Monad (get, evalWith)
We take a closer look at the get construction helper and see how we can use it to lift a function th ...
- [Functional Programming Monad] Map And Evaluate State With A Stateful Monad
We explore our first stateful transaction, by devising a means to echo our state value into the resu ...
- Functional Programming without Lambda - Part 2 Lifting, Functor, Monad
Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...
- Monad (functional programming)
In functional programming, a monad is a design pattern that defines how functions, actions, inputs, ...
随机推荐
- Python并发编程-进程间数据共享
Manager中进程数据不安全 通过加锁解决 from multiprocessing import Manager,Process,Lock def main(dic,lock): lock.acq ...
- Void运算符 与 undefined类型
void 运算符 对给定的表达式进行求值,然后返回 undefined. 何为求值,就是执行之后的表达式. 我们最常见的就是 <a href="javascript: void(0)& ...
- iOS 9的新的改变 iOS SDK Release Notes for iOS 9 说了些改变
iOS 9的新的改变 iOS SDK Release Notes for iOS 9 说了些改变 看了下还算能理解!!!有兴趣可以看看哈!!!不喜勿喷!!后面的对于废除的方法什么有用感觉!!! ...
- python 爬取世纪佳缘,经过js渲染过的网页的爬取
#!/usr/bin/python #-*- coding:utf-8 -*- #爬取世纪佳缘 #这个网站是真的烦,刚开始的时候用scrapy框架写,但是因为刚接触框架,碰到js渲染的页面之后就没办法 ...
- 再谈mobile web retina 下 1px 边框解决方案
本文实际上想说的是ios8下 1px解决方案. 1px的边框在devicePixelRatio = 2的retina屏下会显示成2px,在iphone 6 plug 下,更显示成3px.由其影响美感. ...
- SOJ 4552 [期望,概率]
题目链接:[http://acm.scu.edu.cn/soj/problem.action?id=4552] 题意:给你n种卡牌,每种卡牌有无限多个,每次从中抽取一张卡牌,问:1.集齐这n种卡牌需要 ...
- BZOJ1975 SDOI2010魔法猪学院
就是个A*,具体原理可以参考VANE的博文. 正解要手写堆,会被卡常,也许哪天我筋搭错了写一回吧. #include<bits/stdc++.h> #define r register u ...
- bzoj 1007 半交平面简化版
本题就是求半交平面的交包含哪些直线,而且有点特殊(一般的半交平面用双端队列,因为可能转到最开始的直线,但本题不会,所以只需要一端操作就行了). /*************************** ...
- Codeforces Round #300 D. Weird Chess 水题
D. Weird Chess Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/538/proble ...
- Pylons Controller里面Session.commit()总是出现rollback
Pylons Controller里面执行修改数据库表,总是不成功. 然后通过各种手段: 1.js打印返回值 2.不修改表单提交和修改表单提交,结果比较: 3.通过在Pylons Controller ...