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();
  • 相关阅读:
    JavaWeb下载文件response
    jQuery的prop和attr的区别,及判断复选框是否选中
    【转载并整理】mysql 创建用户,数据库
    【转载】mysql配置模板(my-*.cnf)参数详细说明
    【转载】mysql 热备份
    【转载】centos 安装及配置 mysql5.5.3
    【微信开发】简单的微信分享小插件
    一些http或https请求的参数,什么情况下需要urlencode编码
    sublime在混杂的log数据中提取你想要的内容
    聊聊分布式事务【转】
  • 原文地址:https://www.cnblogs.com/Answer1215/p/13208950.html
Copyright © 2011-2022 走看看