惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
博客园 - 司徒正美
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
量子位
罗磊的独立博客
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
小众软件
小众软件
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园_首页
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
T
Tailwind CSS Blog
IT之家
IT之家
博客园 - 聂微东
Spread Privacy
Spread Privacy
V2EX - 技术
V2EX - 技术
S
Security Affairs
宝玉的分享
宝玉的分享
V
V2EX
C
Cisco Blogs
博客园 - Franky
美团技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
月光博客
月光博客
S
Securelist
J
Java Code Geeks
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
WordPress大学
WordPress大学
W
WeLiveSecurity
T
Threatpost
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
腾讯CDC
阮一峰的网络日志
阮一峰的网络日志

szhshp 的第三边境研究所

假设, AI 把我代替的那一刻真的到来 | szhshp 的第三边境研究所 小傻瓜都能懂的 AstrBot QQ 机器人集成 MCP 功能实战指南 | szhshp 的第三边境研究所 《智人之上: 从石器时代到 AI 时代的信息网络简史》阅读笔记 | szhshp 的第三边境研究所 iPadOS 26 无法设置空间场景图片壁纸的解决方法 | szhshp 的第三边境研究所 《一路云海》(终) | szhshp 的第三边境研究所 《一路云海》(四): 如何不按套路旅行 | szhshp 的第三边境研究所 《一路云海》(三): In Ya Mellow Tone | szhshp 的第三边境研究所 《一路云海》(二): 关西世博参观纪实 | szhshp 的第三边境研究所 《一路云海》(一): 新的征程 | szhshp 的第三边境研究所 2025 大阪世博会 [ 3 天前-先到先得 ] 阶段 场馆预约必中独家攻略 | szhshp 的第三边境研究所 Hackathon 随想 | szhshp 的第三边境研究所 一杯双皮奶 | szhshp 的第三边境研究所 Armbian + CasaOS + NAS 配置指南 | szhshp 的第三边境研究所 Docker 构建镜像报错: error getting credentials - err: exit status 1, out: `` | szhshp 的第三边境研究所 Disqus RIP! 论过高的维护成本如何治疗固执的坏习惯 | szhshp 的第三边境研究所 炸弹猫桌游变体规则 | szhshp 的第三边境研究所 《小岛经济学》阅读笔记 | szhshp 的第三边境研究所 《金钱心理学》阅读笔记 | szhshp 的第三边境研究所 为知笔记 RIP: 迁移剩余的笔记 | szhshp 的第三边境研究所 2025 博客第十年展望 - 再见我的过去 | szhshp 的第三边境研究所 我在独立游戏里面致敬的作品 | szhshp 的第三边境研究所 《How to make thing faster》阅读笔记 | szhshp 的第三边境研究所 《The Art of Clean Code》阅读笔记 | szhshp 的第三边境研究所 《Clean Architecture: A Craftsman Guide to Software Structure and Design》阅读笔记 | szhshp 的第三边境研究所 《How AI Works》阅读笔记 | szhshp 的第三边境研究所 游戏策划废案 - Project Uranus | szhshp 的第三边境研究所 游戏策划废案 - Project X | szhshp 的第三边境研究所 人生第一款独立游戏开发复盘 | szhshp 的第三边境研究所 Trap of Life | szhshp 的第三边境研究所 如果我用手搓了个暗物质雏形 | szhshp 的第三边境研究所 《Rust Programming Language》- EX - Cheatsheet | szhshp 的第三边境研究所 新的播放器上线了 | szhshp 的第三边境研究所 Cypress - End-to-End Testing: OKTA Authentication with MFA | szhshp 的第三边境研究所 VSC x VIM - 反正多学几个快捷键没有坏处 | szhshp 的第三边境研究所 两小时 Docker 速成 - Getting Started | szhshp 的第三边境研究所 《The Joy of Javascript》- 5 - Data | szhshp 的第三边境研究所 《The Joy of Javascript》- 4 - Meta Programming | szhshp 的第三边境研究所 《The Joy of Javascript》- 3 - ADT(Algebraic Data Type) | szhshp 的第三边境研究所 Web-Automation Testing | szhshp 的第三边境研究所 《The Joy of Javascript》- 1 - Object/Function | szhshp 的第三边境研究所 EvalError: Possible side-effect in debug-evaluate | szhshp 的第三边境研究所 前端 QA 工具链指南 - husky,commitlint,commitizen,eslint,typescript,express | szhshp 的第三边境研究所 效率工具 & 软件推荐 | szhshp 的第三边境研究所 站点开源 Project Titan | szhshp 的第三边境研究所 cmd/powershell-命令速查-Cheatsheet | szhshp 的第三边境研究所 Git-命令速查与相关问题解决-Cheatsheet & Troubleshooting | szhshp 的第三边境研究所 Tailwind.css not included in NextJS Production | szhshp 的第三边境研究所 Github GraphQL API - Data Integration | szhshp 的第三边境研究所 尝试 Windows Terminal + z.lua | szhshp 的第三边境研究所 StrokePlus.net - Powerful Hotkey Boost | szhshp 的第三边境研究所 优雅地 Hack 一台黑苹果 | szhshp 的第三边境研究所 一杯关东煮 | szhshp 的第三边境研究所 Gitee x PicGo 管理图床 | szhshp 的第三边境研究所 Create Your Own Redux (Typescript) | szhshp 的第三边境研究所 Getting Started: Ionic + Capacitor + React + Typescript + Android | szhshp 的第三边境研究所 GraphQL: File Upload & Troubleshooting | szhshp 的第三边境研究所 吉祥航空随心飞刷票工具循环查票工具 | szhshp 的第三边境研究所 NVM Windows Portable Installation | szhshp 的第三边境研究所 NextJS x Typescript - Integration & Troubleshooting | szhshp 的第三边境研究所 全站点升级 - Project Titan | szhshp 的第三边境研究所 AWS-EC2-常见问题解决-Troubleshooting | szhshp 的第三边境研究所 Workbox-Getting Started | szhshp 的第三边境研究所 《时间简史》阅读笔记 | szhshp 的第三边境研究所 《时间的秩序》阅读笔记 | szhshp 的第三边境研究所 ESLint-常见问题解决-Troubleshooting | szhshp 的第三边境研究所 站点索引 | szhshp 的第三边境研究所 个人知识库搭建 - Hexo 实现 Github/Coding 持续集成 | szhshp 的第三边境研究所 BMOB-常见问题解决-Troubleshooting | szhshp 的第三边境研究所 React + Typescript: 开启 HMR/Hot Loader | szhshp 的第三边境研究所 Yarn & NPM | szhshp 的第三边境研究所 ESLint: Typescript + React + TSX 集成 | szhshp 的第三边境研究所 《10101》EP15:过年 2020 | szhshp 的第三边境研究所 Cmder-Usage | szhshp 的第三边境研究所 Redux-DOM not refreshed | szhshp 的第三边境研究所 React Semantic UI-CheatSheet | szhshp 的第三边境研究所 Typescript: Getting Started | szhshp 的第三边境研究所 Flutter-Getting Started | szhshp 的第三边境研究所 Typescript: Access window object with type check | szhshp 的第三边境研究所 VSC Extension Development-Create A Code Formatter Extension | szhshp 的第三边境研究所 OneNote Extension-Main API | szhshp 的第三边境研究所 TortoiseGit Win10 Icon not showing correctly | szhshp 的第三边境研究所 Mongoose: aggregate() 方法实现聚合函数 | szhshp 的第三边境研究所 React In Depth - React 源码解析 - render() & Fiber | szhshp 的第三边境研究所 MongoDB x Mongoose: 实现类似 Join 的功能 | szhshp 的第三边境研究所 Disqus 评论框改造工程-实现 Disqus 代理的 Serverless 服务 | szhshp 的第三边境研究所 GUI, CLI, Terminal, Shell, TTY, Console, Bash | szhshp 的第三边境研究所 Jest Async Best Practise: No Nested Async | szhshp 的第三边境研究所 关系型数据库与非关系型数据库优缺点分析 | szhshp 的第三边境研究所 New Edge & Chromium Error - Package is invalid: 'CRX_VERSION_NUMBER_INVALID' | szhshp 的第三边境研究所 选择 GraphQL 的 N 个理由 | szhshp 的第三边境研究所 StrokePlus - 鼠标手势神器的代码编写技巧 | szhshp 的第三边境研究所 嗨,好久不见 | szhshp 的第三边境研究所 Vue + ElementUI 集成 Vue Router | szhshp 的第三边境研究所 IE8 - Unknown Runtime Error Using innerHTML & Ajax | szhshp 的第三边境研究所 React: Handling Events | szhshp 的第三边境研究所 React-Navigation Integration with Redux | szhshp 的第三边境研究所 React: States is tricky | szhshp 的第三边境研究所 《10101》EP14:小剧场 | szhshp 的第三边境研究所 ColdFusion - Basic - arguments in cffunction | szhshp 的第三边境研究所 ColdFusion - Basic - cfset | szhshp 的第三边境研究所
《The Joy of Javascript》- 2 - Functor/Monad | szhshp 的第三边境研究所
2022-06-20 · via szhshp 的第三边境研究所

Meta

目录

相关文章

一本书里面内容较多, 因此分成了多篇 Post, 可以从此处看到相关文章:

Functor & Monad | 函子和单子

实现 FP 需要保证一些函数的输入和输出规范化. 以方便 compose 进行链式调用.

例如: arr.map(x=>x+1).map(x=>x+2) 就是因为 .map() 方法的输入输出的规范化以使得其可以链式调用, 多个 map 方法可以进行 compose: const testMethod = compose(map(capitalize), map(getAscii));

Functor

Functor 的特性

  1. A functor is anything (such as an object) that can be mapped over or that implements the map interface properly
  2. 函数式编程不直接操作值, 而是由函子完成
  3. 行为类似于一个容器, 容器会包裹不同的输入, 之后会返回一个统一的结构 (A Functor is a container which can be mapped upon by a Unary function.)

原生的 Array 类型就是一个 Functor

[1, 2, 3, 4].map(add).map(add)  

Functor 的设计原则

  1. identity: 如果给 map 传递一个返回自己的方法, 那么得到的结果和自身相等
    • F.map(x=>x) === F
  2. composition: 多个方法可以进行链式调用, 比如下方的 f(g(x)) 可以写成 f.map(g).map(x)
    • F.map((x) => f(g(x))) === F.map(g).map(f)

Functor 实例

一般会实现以下属性和方法: 1. _value : 通过这个属性从容器中取得实际的值 2. of() : 给方法提供初始值 3. map() : map 方法接收一个 fn, fn 去得到一个新的值

class Container {
  static of(value) {
    return new Container(value)
  }
  constructor(value) {
    this._value = value
  }
  map(fn) {
    return Container.of(fn(this._value))
  }
}

let c = Container.of(5)
  .map((x) => x * x)
  .map((x) => x + 2)

console.log(c) // Container { _value: 27 }

More Functor Example

Functor with Mixin
const Functor = {
  map(f = identity) {
    /* 注意当前 Functor 需要用到 Container 的 get 方法 (因为 val 设置成了 private), 所有扩展了这个 Functor 的类都需要拥有这个 get 方法 */
    return this.constructor.of(f(this.get()));
  },
};

const double = (x) => x * 2;
const triple = (x) => x * 3;

class Container {
  #val;  /* 注意这个地方的 val 是 private, 因此必须使用 get 方法才能够得到对应的值. */
  constructor(value) {
    this.#val = value;
  }
  static of(value) {
    return new Container(value);
  }

  get() {
    return this.#val;
  }
}

Object.assign(Container.prototype, Functor);

console.log(Container.of(2).get()); /* 2 */
console.log(Container.of(2).map(double).get()); /* 4 */
console.log(Container.of(2).map(double).map(triple).get()); /* 12 */
Maybe Functor
class Maybe {
  static of(value) {
    return new Maybe(value);
  }
  constructor(value) {
    this._value = value;
  }
  map(fn) {
    /* 在这个地方进行了一些特殊的处理 */
    return this.isNothing() ? Maybe.of(null) : Maybe.of(fn(this._value));
  }
  isNothing() {
    return this._value === null || this._value === undefined;
  }
}

let obj = new Maybe(5)
  .map((x) => null)  /* 此处对应的值已经转化成了 null */
  .map((x) => x * x);

console.log(obj);

Monad

Monad 的特性

  • Monad 也是类似函子的概念, 区别在于有时候函子的返回值不是我们需要的类型
    • 使用 compose 要求输入和输出一致比如 number -> number
    • 但是有一些操作会返回更多的类型比如 number -> number[]
      • 这个时候需要一个 flatMap 方法进行拍平
    • 又或者可能会出现返回嵌套类型比如 number -> { res: number }
      • 这个时候可能需要对 Object 进行额外的 mapping
  • Monad 就是通过一个额外的方法来将返回不一致的情况进行处理, 使其方便后期 compose 复合操作

Monad 的设计原则

注意 chain 方法根据不同的实现可能会有不同的名称

  • Left identity: M.of(a).chain(f) === f(a)
  • Right identity: m.chain(M.of) === m
  • Associativity: m.chain(f).chain(g) === m.chain(x => f(x).chain(g))

Monad 实例

/* Number -> Number[], 如果连续调用将会得到多层嵌套数组 */
var f = (x) => [x ** 2];
var g = (x) => [x * 3];

/* Monad Container */
var Container = class {
  of(value) {
    return new Container(value);
  }

  constructor(value) {
    this.value = value;
  }

  map(f) {
    return new Container(f(this.value));
  }

  chain(f) {
    /* 此处对于 Functor 的 map 进行了一些额外操作 */
    /* 这个方法根据需求不同会有不同实现, 比如对一些 side effect 的处理. */
    return new Container(f(this.value).flat()[0]);
  }
};

var test = new Container(2);

// test.of(2).map(f).map(g); // 报错, Functor 的 map 方法无法处理数组

test.of(2).chain(f).chain(g); // Container { value: 12 } 

Interoperation with Class | 给 Class 扩展 Functor 和 Monad

const Functor = {
  map(f = identity) {
    return this.constructor.of(f(this.get()));
  },
};


/* 将 Functor 扩展到 Monad 中 */
const Monad = Object.assign({}, Functor, {
  flatMap(f) {
    return this.map(f).get();
  },
});

/* 如此一来 SomeClass 就同时拥有了 map 和 flatMap, SomeClass 就成为了一个 Monad */
Object.assign(SomeClass.prototype, Functor, Monad);

Summary

  • JavaScript offers behavior delegation via implicit links and mixins for building objects in a compositional manner.
  • Behavior delegation is the natural way to model objects in JavaScript. It uses the implicit delegation mechanism present in JavaScript’s lookup process and the prototype chain.
  • Object concatenation offers a simple approach based on structural object composition, which allows you to build objects by attaching (embedding) behavior from other independent objects.
  • You can use mixins to extend objects (or classes) dynamically and favor structural composition over inheritance.
  • Mixins address the issue of multiple inheritance through a mechanism known as mixin linearization.
  • JavaScript offers a shortcut for Object.assign by using the spread operator, although Object.assign and the spread operator are not interchangeable.