[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之路【第一篇】:介绍、基本语法、流程控制
一.python 简介 python 特点 Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,适合初学者的Basic语言,适合网 ...
- 微信小程序setData()对数组的操作
对于setData普通数据类型而言,没什么讲究 但是对于数组而言,再直接修改一个完整的数组显得有些多余,首先写着不简易,其次效率很是滴. 比如 你都能觉得复杂,官方肯定是有对应的优化的. 官方demo ...
- MPI - 缓冲区和非阻塞通信
转载自: Introduction to MPI - Part II (Youtube) Buffering Suppose we have ) MPI_Send(sendbuf,...,,...) ...
- Cable master POJ - 1064
Inhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Commi ...
- [BZOJ4876][ZJOI2017]线段树
没有用到任何算法,代码只有60+行,但是细节多如牛毛,各种分类讨论必须全部想清楚才行. https://www.cnblogs.com/xiejiadong/p/6811289.html #inclu ...
- CodeForces - 1017D The Wu
题面在这里! 比较显而易见的暴力,O(2^(2n) + 2^n * 100) 就可以直接做了 #include<bits/stdc++.h> #define ll long long us ...
- JS取整,四舍五入,取绝对值等Math对象常用方法
function f1(type,num1) { switch(type) { case 'floor': return Math.floor(num1);//取整或下舍入 break; case ' ...
- Newtonsoft.Json序列化和反序列
这里下载:http://www.newtonsoft.com/products/json/安装: 1.解压下载文件,得到Newtonsoft.Json.dll 2.在项目中添加引用.. 序列化 ...
- Ext.form.ComboBox常用属性详解
Ext.form.ComboBox常用属性详解 标签: Extjs js combo js 代码 var combo = new Ext.form.ComboBox({ store : new Ext ...
- ios学习笔记图片+图片解释(c语言 oc语言 ios控件 ios小项目 ios小功能 swift都有而且笔记完整喔)
下面是目录其中ios文件夹包括了大部分ios控件的介绍和演示,swift的时完整版,可以学习完swift(这个看的是swift刚出来一周的视频截图,可能有点赶,但是完整),c语言和oc语言的也可以完整 ...