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();
  • 相关阅读:
    微服务化之无状态化与容器化
    微服务化的不同阶段 Kubernetes 的不同玩法
    网易大数据技术沙龙
    十年•杭研技术秀 | “网易云存储服务”从0到1发展之路
    传统业务上云:跨AZ容灾架构解析
    kubernetes1.9管中窥豹-CRD概念、使用场景及实例
    浅谈 kubernetes service 那些事 (下篇)
    浅谈 kubernetes service 那些事(上篇)
    Docker容器的原理与实践(上)
    Docker容器的原理与实践 (下)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/13208950.html
Copyright © 2011-2022 走看看