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 Mof 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.

More detail

[Functional Programming] Monad的更多相关文章

  1. [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 ...

  2. [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 ...

  3. [Functional Programming Monad] Combine Stateful Computations Using Composition

    We explore a means to represent the combination of our stateful computations using familiar composit ...

  4. [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 ...

  5. [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 ...

  6. [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 ...

  7. [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 ...

  8. Functional Programming without Lambda - Part 2 Lifting, Functor, Monad

    Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...

  9. Monad (functional programming)

    In functional programming, a monad is a design pattern that defines how functions, actions, inputs, ...

随机推荐

  1. ssm+RESTful bbs项目后端主要设计

    小谈: 帖主妥妥的一名"中"白了哈哈哈.软工的大三狗了,也即将找工作,怀着丝丝忐忑接受社会的安排.这是第一次写博客(/汗颜),其实之前在学习探索过程中,走了不少弯路,爬过不少坑.真 ...

  2. 深入理解javascript作用域系列第二篇

    前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极易出错.这实际上是由两种作用域工作 ...

  3. java8新特性——四大内置核心函数式接口

    在前面几篇简单介绍了一些Lambda表达式得好处与语法,我们知道使用Lambda表达式是需要使用函数式接口得,那么,岂不是在我们开发过程中需要定义许多函数式接口,其实不然,java8其实已经为我们定义 ...

  4. 前缀和:CodeForces 932B Recursive Queries

    Description Let us define two functions f and g on positive integer numbers. You need to process Q q ...

  5. CSS 笔记——阴影、圆角、旋转、光标

    7. 阴影.圆角.旋转.光标 (1)box-shadow 阴影 基本语法 text-shadow: h-shadow v-shadow blur color; box-shadow: h-shadow ...

  6. 51nod1437 迈克步 单调栈

    考虑一个点作为最小值的区间$[L[i], R[i]]$ 那么这个区间的所有含$i$的子区间最小值都是$v[i]$ 因此,用单调栈求出$L[i], R[i]$后,对$R[i] - L[i] + 1$这个 ...

  7. [BZOJ4009][HNOI2015]接水果(整体二分)

    [HNOI2015]接水果 时间限制:60s      空间限制:512MB 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The b ...

  8. 【计算几何】【二分图判定】Gym - 101485C - Cleaning Pipes

    题意:有n个水井,每个水井发出一些管线(都是线段),然后每条管线上最多只有一个水井.所有从不同的水井发出的管线的相交点都是清洁点(不存在清洁点是大于两条管线点的交点).你需要在某些管线上放出一些机器人 ...

  9. 2017-2018-1 JAVA实验站 第二周作业

    2017-2018-1 JAVA实验站 第二周作业 小组成员: 组长 20162318张泰毓 成员 20162303石亚鑫 20162304张浩林 20162307张韵琪 20162321王彪 201 ...

  10. AtCoder Beginner Contest 022 A.Best Body 水题

    Best Body Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://abc022.contest.atcoder.jp/tasks/abc02 ...