[Function Programming] Function modelling -- 9. Monad Transformers

Path: Compose Functors -> Monad Transformers -> Free Monad

 

Let's first see how much it sucks when dealing with nested Monads (without natural transformation).

复制代码
const { TaskT, Task, Either } = require("../types");
const _ = require("lodash");

const users = [
  { id: 1, name: "Brian" },
  { id: 2, name: "Marc" },
  { id: 3, name: "Odette" },
];
const following = [
  { user_id: 1, follow_id: 3 },
  { user_id: 1, follow_id: 2 },
  { user_id: 2, follow_id: 1 },
];

const find = (table, query) =>
  Task.of(Either.fromNullable(_.find(table, query)));

const app = () =>
  find(users, { id: 1 }) // Task(Either(User))
    .chain((eitherUser) =>
      eitherUser.fold(Task.rejected, (user) =>
        find(following, { follow_id: user.id })
      )
    )
    .chain((eitherUser) =>
      eitherUser.fold(Task.rejected, (foUser) =>
        find(users, { id: foUser.user_id })
      )
    )
    .fork(console.error, (eu) => eu.fold(console.error, console.log));

app(); // { id: 2, name: 'Marc' }
复制代码

 

As you can see, the code is trying to find your follower's follower. 

Each time we need to .chain() + .fold()... 

Then .fork() + .fold()...

Which is confusing.

 

To solve the problem, we can include Monad transform:

const TaskEither = TaskT(Either);

Redefine 'find' function:

const find = (table, query) =>
  TaskEither.lift(Either.fromNullable(_.find(table, query)));

 

Difference between .of() vs .lift():

// TaskEither.of(Either) --> Task(Either(Either))
// TaskEither.lift(Either) --> Task(Either)

 

Then we can simpify our app:

const app = () =>
  find(users, { id: 1 }) // Task(Either(User))
    .chain((user) => find(following, { follow_id: user.id }))
    .chain((foUser) => find(users, { id: foUser.user_id }))
    .fork(console.error, (eu) => eu.fold(console.log, console.log));

app();

 -- 

 

Full ocde:

复制代码
const { TaskT, Task, Either } = require("../types");
const _ = require("lodash");

const TaskEither = TaskT(Either);

const users = [
  { id: 1, name: "Brian" },
  { id: 2, name: "Marc" },
  { id: 3, name: "Odette" },
];
const following = [
  { user_id: 1, follow_id: 3 },
  { user_id: 1, follow_id: 2 },
  { user_id: 2, follow_id: 1 },
];

const find = (table, query) =>
  TaskEither.lift(Either.fromNullable(_.find(table, query)));

const app = () =>
  find(users, { id: 1 }) // Task(Either(User))
    .chain((user) => find(following, { follow_id: user.id }))
    .chain((foUser) => find(users, { id: foUser.user_id }))
    .fork(console.error, (eu) => eu.fold(console.log, console.log));

app();
复制代码

 

posted @   Zhentiw  阅读(169)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2017-06-29 [WASM] Read WebAssembly Memory from JavaScript
2017-06-29 [WASM] Call a JavaScript Function from WebAssembly
2016-06-29 [Webpack 2] Ensure all source files are included in test coverage reports with Webpack
2016-06-29 [Webpack 2] Add Code Coverage to tests in a Webpack project
点击右上角即可分享
微信分享提示