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. 【BZOJ 2121】 (字符串DP,区间DP)

    2121: 字符串游戏 Description BX正在进行一个字符串游戏,他手上有一个字符串L,以及其他一些字符串的集合S,然后他可以进行以下操作:对于一个在集合S中的字符串p,如果p在L中出现,B ...

  2. hdu 3089 (快速约瑟夫环)

    Josephus again Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  3. Problem F: 深入浅出学算法007-统计求和

    Description 求含有数字a且不能被a整除的4位整数的个数,并求这些整数的和 Input 多组测试数据,先输入整数T表示组数然后每组输入1个整数a(1<=a<=9) Output ...

  4. bzoj 4769: 超级贞鱼 -- 归并排序

    4769: 超级贞鱼 Time Limit: 1 Sec  Memory Limit: 128 MB Description 马达加斯加贞鱼是一种神奇的双脚贞鱼,它们把自己的智慧写在脚上——每只贞鱼的 ...

  5. JDK源码(1.7) -- java.util.AbstractCollection<E>

    java.util.AbstractCollection<E> 源码分析(JDK1.7) ------------------------------------------------- ...

  6. Qt on android 蓝牙开发(控制小车)

    因为要做一个用蓝牙控制小车的app,就用着QT搞了下,网上关于QT蓝牙开发的资料比较少,我在这里记录下过程希望对看到了人有所帮助 首先在项目文件里添加 QT += bluetooth 这样就可以用QT ...

  7. Matlab 曲线绘制之线型和颜色 示例

    估计很多人会碰到,当绘制的曲线特别多的时候,需要用不同的颜色和线型区分开这些曲线.根据STC论文,自己整理了一个颜色和线型的例子,供大家直接使用,直接引用PlotStyle这个数据结构就可以了. 示例 ...

  8. 点广告获取一些BTC(比特币)的网站

      免费获取比特币:http://freebtc.qiniudn.com/freebtc.html   free btc:http://freebtc.qiniudn.com/freebtc.html ...

  9. URL资源跨域访问 跨域使用session信息

    SilverLight 出于对安全性的考虑默认情况下对URL的访问进行了严格的限制,只允许访问同一子域下的URL资源. 下表列出了Silverlight 2.0 中 URL 访问规则:   WebCl ...

  10. linux下使用crontab创建定时任务

    在linux中启动crontab服务: /etc/init.d/crond start crontab的命令格式 crontab -l 显示当前的crontab 文件(默认编写的crontab文件会保 ...