首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场

Monad

作者头像
lambeta
发布于 2018-08-17 03:40:50
发布于 2018-08-17 03:40:50
1.6K00
代码可运行
举报
文章被收录于专栏:编舟记编舟记
运行总次数:0
代码可运行

Monad不就是个自函子范畴上的幺半群,这有什么难理解的(A monad is just a monoid in the category of endofunctors) —— Phillip Wadler

自函子(Endofunctor)

什么是函数(Function)? 函数表达的映射关系在类型上体现在特定类型(proper type)之间的映射。

什么是自函数(Endofunction)?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
identity :: Number -> Number

自函数就是把类型映射到自身类型。函数identity是一个自函数的特例,它接收什么参数就返回什么参数,所以入参和返回值不仅类型一致,而且值也相同。

接下来,回答什么是自函子(Endofunctor)之前,我们先弄清什么是函子(Functor)?

函子有别于函数,函数描述的是特定类型(proper type)之间的映射,而函子描述的是范畴(category)之间的映射。

那什么是范畴(category)?

我们把范畴看做一组类型及其关系态射(morphism)的集合。包括特定类型及其态射,比如Int、String、Int -> String;高阶类型及其态射,比如List[Int]、List[String]、List[Int] -> List[String]

接下来看看函子是如何映射两个范畴的,见下图:

范畴

图中范畴C1和范畴C2之间有映射关系,C1中Int映射到C2中的List[Int],C1中String映射到C2中的List[String]。除此之外,C1中的关系态射Int -> String也映射到C2中的关系List[Int] -> List[String]态射上。

换句话说,如果一个范畴内部的所有元素可以映射为另一个范畴的元素,且元素间的关系也可以映射为另一个范畴元素间关系,则认为这两个范畴之间存在映射。所谓函子就是表示两个范畴的映射。

澄清了函子的含义,那么如何在程序中表达它?

在Haskell中,函子是在其上可以map over的东西。稍微有一点函数式编程经验,一定会想到数组(Array)或者列表(List),确实如此。不过,在我们的例子中,List并不是一个具体的类型,而是一个类型构造子。举个例子,构造List[Int],也就是把Int提升到List[Int],记作Int -> List[Int]。这表达了一个范畴的元素可以映射为另一个范畴的元素。

List具有map方法,不妨看看map的定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f :: A -> B
map :: f -> List[A] -> List[B]

具体到我们的例子当中,就有:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f :: Int -> String
map :: f -> List[Int] -> List[String]

展开来看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
map :: Int -> String -> List[Int] -> List[String]

map的定义清晰地告诉我们:Int -> String这种关系可以映射为List[Int] -> List[String]这种关系。这就表达了元素间的关系也可以映射为另一个范畴元素间关系。

所以类型构造器List[T]就是一个函子。

理解了函子的概念,接着继续探究什么是自函子。我们已经知道自函数就是把类型映射到自身类型,那么自函子就是把范畴映射到自身范畴。

自函子是如何映射范畴的,见下图:

Identity自函子范畴

图中表示的是一个将范畴映射到自身的自函子,而且还是一个特殊的Identity自函子。为什么这么说?从函子的定义出发,我们考察这个自函子,始终有List[Int] -> List[Int]以及List[Int] -> List[String] -> List[Int] -> List[String]这两种映射。 我们表述成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
类型List[Int]映射到自己
态射f :: List[Int] -> List[String]映射到自己

我们记作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
F(List[Int]) = List[Int]
F(f) = f
其中,F是Functor.

除了Identity的自函子,还有其它的自函子,见下图:

自函子范畴

图中的省略号代表这些范畴可以无限地延伸下去。我们在这个大范畴所做的所有映射操作都是同一范畴内的映射,自然这样的范畴就是一个自函子的范畴。

我们记作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List[Int] -> List[List[Int]]
List[Int] -> List[String] -> List[List[Int]] -> List[List[String]]
...

所以List[Int]、List[List[Int]]、...、List[List[List[...]]]及其之间的态射是一个自函子的范畴。


幺半群

[幺半群][1]是一个带有二元运算 : M × M → M 的集合 M ,其符合下列公理: 结合律:对任何在 M 内的a、b、c, (ab)c = a(bc) 。 单位元:存在一在 M 内的元素e,使得任一于 M 内的 a 都会符合 ae = e*a = a 。

接着我们看看在自函子的范畴上,怎么结合幺半群的定义得出Monad的。

假设我们有个cube函数,它的功能就是计算每个数的3次方,函数签名如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cube :: Number -> Number

现在我们想在其返回值上添加一些调试信息,所以返回一个元组(Tuple),第二个元素代表调试信息。函数签名如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f :: Number -> (Number,String)

入参和出参不一致,这会产生什么影响?我们看看幺半群的定义中规定的结合律。对于函数而言,结合律就是将函数以各种结合方式嵌套起来调用。我们将常用的compose函数看作此处的二元运算。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var compose = function(f, g) {
  return function(x) {
    return f(g(x));
  };
};

compose(f, f)

从函数签名可以很容易看出,右边的f运算的结果是元组,而左侧的f却是接收一个Number类型的函数,它们是彼此不兼容的。

有什么好办法能消除这种不兼容性?结合前面所讲,cube是一个自函数Number -> Number,而元组(Number,String)在Hask范畴是一个自函子,理由如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
F Number = (Number,String) 
F Number -> Number = (Number,String) -> (Number,String)

假如输入和输出都是元组,结果会如何呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fn :: (Number,String) -> (Number,String)

compose(fn, fn)  

这样是可行的!在验证满足结合律之前,我们引入一个bind函数来辅助将f提升成fn.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f :: Number -> (Number,String) => fn :: (Number,String) -> (Number,String)
: 在Haskell中称为 liftM
var bind = function(f) {
  return function F(tuple) {
    var x  = tuple[0],
        s  = tuple[1],
        fx = f(x),
        y  = fx[0],
        t  = fx[1];

    return [y, s + t];
  };
};

我们来实现元组自函子范畴上的结合律:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var cube = function(x) {
  return [x * x * x, 'cube was called.'];
};

var sine = function(x) {
  return [Math.sin(x), 'sine was called.'];
};

var f = compose(compose(bind(sine), bind(cube)), bind(cube));
f([3, ''])

var f1 = compose(bind(sine), compose(bind(cube), bind(cube)));
f1([3,''])
>>>
[0.956, 'cube was called.cube was called.sine was called.']
[0.956, 'cube was called.cube was called.sine was called.']

这里f和f1代表的调用顺序产生同样的结果,说明元组自函子范畴满足结合律。

那如何找到这样一个e,使得a*e=e*a=a,此处的*compose运算

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// unit :: Number -> (Number,String)
var unit = function(x) { return [x, ''] };

var f = compose(bind(sine), bind(cube));

compose(f, bind(unit)) = compose(bind(unit), f) = f

这里的bind(unit)就是e了。

到这里,思路逐步清晰了。在Haskell这类的强类型语言中,我们甚至可以组装自己的Tuple Monad。如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Tuple(Number,String)
flatmap :: Tuple -> Number -> Tuple -> Tuple
unit :: Number -> Tuple
map :: Tuple >>= unit
    :: Tuple -> Number -> Number -> Tuple

//compose
// flatmap 即 bind,中缀表达式一般是 >>=
Tuple >>= (Number -> Tuple) >>= (Number -> Tuple)

Monads for functional programming一书中介绍说monad是一个三元组(M, unit, *),对应此处就是(Tuple, unit, bind).

参考链接:

  1. Translation from Haskell to JavaScript of selected portions of the best introduction to monads I've ever read
  2. 我所理解的monad
  3. Monads for functional programming
  4. Functor, Applicative, Monad
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016.07.16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
whistle手机调试工具使用简单教程
启动之后,输入127.0.0.1:8899 就可以访问到whistle调试界面了:
蓓蕾心晴
2019/08/21
2.2K0
whistle手机调试工具使用简单教程
前端应该知道的web调试工具——whistle
第一,whistle 是一个 web 调试代理工具,它的功能十分强大。作为一名前端,我们需要经常跟协议中的应用层打交道,Mock 数据、跨域问题、cookie 的修改、移动端调试等等,都是我们必备的技能,而 whistle 就能解决其中 90% 的问题
GopalFeng
2020/09/24
2.6K0
前端应该知道的web调试工具——whistle
前端开发的利器,使用Whistle提升开发幸福感
好多人认为whistle是抓包工具,殊不知抓包只是whistle能力的冰山一角。除了抓包外,它还能修改请求与响应、真机调试h5移动端、解决跨域、域名映射等等等。总而言之,使用whistle能够提升我们的开发效率,改善开发体验。
winty
2024/04/15
4780
前端开发的利器,使用Whistle提升开发幸福感
⭐️入职新公司需要准备哪些工作,如何让同事觉得你是大神
基本理清这些平台就足够了,一般公司都是会在新人入职文档写明,如果没有,那就得一个一个去问。
linwu
2023/07/27
5470
⭐️入职新公司需要准备哪些工作,如何让同事觉得你是大神
抓包工具——charles
Proxy -> SSL Proxying Settings 勾选 Enable SSL Proxying, Host : _ (使用通配符表示检测所有网络请求;建议还是设置单个需要抓取的 https host,尽量避免使用 _ 通配符) Port:443
leader755
2022/03/09
1.2K0
抓包工具——charles
whistle——基于Node实现的跨平台web调试代理工具
不同于其他抓包工具(通过断点修改请求响应的方式),whistle采用的是类似配置系统hosts的方式,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式。
毛大姑娘
2020/12/28
1.1K0
【抓包工具】whistle入门
抓包就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,常用来检验前后端传输数据的情况,常用的抓包工具有Fiddler、Charles、wireshark,不过接下来我要分享是另一个非常易上手的抓包工具----whistle。
用户9913368
2022/08/13
1.7K0
【抓包工具】whistle入门
一探究竟!Whistle拦截HTTPS是如何实现的?
导语 | 本文主要介绍Whistle的实现原理,通过这篇文章读者可以了解Whistle的具体实现过程,并且自己也可以实现一个简单的抓包调试工具。 项目Github地址:https://github.com/avwo/whistle Whistle是基于Node实现的跨平台Web抓包调试(HTTP)代理,主要功能: 实时抓包:支持HTTP、HTTPS、HTTP2、WebSocket、TCP等常见Web请求 修改请求响应:与一般抓包调试工具采用断点的方式不同,Whistle采用类似系统host的配置规则方
腾讯云开发者
2021/12/22
2.9K0
whistle工具全程入门
IMWeb前端团队
2017/12/29
2.7K0
whistle工具全程入门
一款基于中间人攻击用于偷窥HTTPs网站流量的秘密代理工具
我常用的网络分析工具有:Fiddler、Charles 、whistle 、WireShark 和 Tcpdump
快乐咸鱼每一天
2019/10/14
5K0
一款基于中间人攻击用于偷窥HTTPs网站流量的秘密代理工具
Whistle 实现原理 —— 从 0 开始实现一个抓包工具
导语 通过这篇文章可以大致了解 Whistle 的实现原理,并学习如何实现一个简单的抓包调试工具。 项目 Github 地址:https://github.com/avwo/whistle Whistle 是基于 Node.js 实现的跨平台 Web 抓包调试(HTTP)代理,主要功能: 实时抓包:支持 HTTP、HTTPS、HTTP2、WebSocket、TCP 等常见 Web 请求的抓包; 修改请求响应:与一般抓包调试工具采用断点的方式不同,Whistle 采用类似系统 host 的配置规则方式; 扩展
用户1097444
2022/06/29
1.4K0
Whistle 实现原理 —— 从 0 开始实现一个抓包工具
一文读懂H5移动开发调试技巧
内容来源:作者 | Jartto,http://jartto.wang/2018/11/01/mobile-debug/
IT大咖说
2018/12/24
1.6K0
一文读懂H5移动开发调试技巧
Charles抓包工具
Charles是一个HTTP代理工具,使开发人员能够查看客服端和服务器之间的所有HTTP/ HTTPS/SSL网络请求。 Charles是在PC环境下常用的网络抓包截取工具,在做移动开发时,我们为了调试客户端与服务端的网络通讯协议,常常需要截取网络请求来分析。
清风穆云
2021/08/09
1.7K0
高颜值抓包工具Charles,实现Mac和IOS端抓取https请求
Hi,大家好。在进行测试的过程中,不可避免的会有程序报错,为了能更快修复掉Bug,我们作为测试人员需要给开发人员提供更准确的报错信息或者接口地址,这个时候就需要用到我们的抓包工具。
可可的测试小栈
2022/06/06
2.8K0
高颜值抓包工具Charles,实现Mac和IOS端抓取https请求
安卓抓包,为何总是 Tunnel to?
最近两周我学了下安卓逆向,还要学下学校的课程,感觉再不学就要没了,而且个人也有点事,所以文章更新给耽误了。学了点安卓逆向之后,就需要应用,要不学了也是浪费时间。
sergiojune
2019/05/14
3.7K0
安卓抓包,为何总是 Tunnel to?
Charles抓包工具简单教程
在实际开发、测试中需要代理截取app的网络请求报文来快速定位问题,https双向认证的APP越来越多,fiddler在这方面并不好用。由于windows系统较多,编写此博客作为windows版的使用指南,其中包含了一些简易的使用,安装https证书抓包,常用的设置,以及弱网测试,下列都会详细讲解,内容为本人的测试经验,不足之处还望补充~
全栈程序员站长
2022/07/01
1.2K0
Charles抓包工具简单教程
前端开发必须知道的抓包神器!
好多人认为whistle是抓包工具,殊不知抓包只是whistle能力的冰山一角。除了抓包外,它还能修改请求与响应、真机调试h5移动端、解决跨域、域名映射等等等。总而言之,使用whistle能够提升我们的开发效率,改善开发体验。
zz_jesse
2024/03/19
1K0
前端开发必须知道的抓包神器!
最全的 Charles 抓包工具详解「建议收藏」
不管是移动开发者还是测试者,于抓包工具对于我们的工作都是非常有帮助的,而Charles是一款非常优秀的抓包工具
全栈程序员站长
2022/07/02
11.7K0
最全的 Charles 抓包工具详解「建议收藏」
Whistle抓包工具指南
Whistle 是一个基于 Node.js 的跨平台抓包调试代理工具。它不仅支持 HTTP 和 HTTPS 请求的截获和修改,还支持 WebSocket、TCP 等多种协议。通过简单的配置,开发者可以轻松实现流量监控、数据篡改、请求转发、Mock 数据等功能。
王震宇
2024/07/02
1.9K0
Whistle抓包工具指南
HTTP接口抓包工具之Fiddler
Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据,Fiddler包含了一个强大的基于时间脚本的子系统,并且能使用.NET语言进行扩展。对HTTP协议越了解,就能越掌握Fiddler的使用方法。越使用Fiddler,就越能帮助了解HTTP协议。Fiddler无论对开发人员或者测试人员来说,都是非常有用的工具。
测试开发社区
2019/09/20
2.2K0
HTTP接口抓包工具之Fiddler
推荐阅读
相关推荐
whistle手机调试工具使用简单教程
更多 >
交个朋友
加入前端学习入门群
前端基础系统教学 经验分享避坑指南
加入腾讯云技术交流站
前端技术前沿探索 云开发实战案例分享
加入前端趋势交流群
追踪前端新趋势 交流学习心得
换一批
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验