• [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();
  • 相关阅读:
    JAVA常见面试题之Forward和Redirect的区别
    springMVC学习笔记(二)-----注解和非注解入门小程序
    springMVC学习笔记(一)-----springMVC原理
    C语言关键字
    JAVA HASHMAP 如何用
    java中HashMap详解
    java中dao层和service层的区别是什么?
    到底DAO是什么?为什么要有它的存在?
    Ubuntu命令基础
    使用VMWare12.0安装Ubuntu系统
  • 原文地址:https://www.cnblogs.com/Answer1215/p/13208950.html
Copyright © 2020-2023  润新知