zoukankan      html  css  js  c++  java
  • [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();
  • 相关阅读:
    2-5 Flutter开发环境与Android开发环境设置详解(Windows)
    2-3 Flutter开发环境与iOS开发环境设置(Mac)
    2-1 本章作业&2-2 开发系统与工具选择
    ASP.NET Core会议管理平台实战_4、参数校验、操作结果封装,注册参数配置
    ASP.NET Core会议管理平台实战_3、认证、授权表迁移
    29.镜像容器与仓库
    27.集成EFCore配置Client和API
    26.OpenIdConnect获取用户信息的两种方式
    25.ProfileService实现(调试)
    24.集成ASP.NETCore Identity
  • 原文地址:https://www.cnblogs.com/Answer1215/p/13208950.html
Copyright © 2011-2022 走看看