zoukankan      html  css  js  c++  java
  • [Ramda] Lens in Depth

    In this post, we are going to see how to use Ramda Lens.

    For example, we have data:

    const {log} = require('./lib/log');
    const R = require('ramda');
    
    const band = {
        name: 'K.M.F.D.M',
        members: {
            current: [
                {name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
                {name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
                {name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
                {name: 'Steve While', plays: ['guitar']}
            ],
            past: [
                {name: 'Raymond Watts', plays: ['vocals', 'synth']},
                {name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
                {name: 'Gunter', plays: ['guitar', 'synth']}
            ]
        }
    };

    R.lens:

    R.lens takes a getter and a setter: 

    const name = R.lens(R.prop('name'), R.assoc('name'));
    log(R.view(name, band)); // K.M.F.D.M
    log(R.set(name, 'M.D.F.M.K', band));

    R.lensProp: 

    There is a shorter way to do getter/setter partten:

    const name = R.lensProp('name');
    const makeLower = a => a.toLowerCase();
    log('over lensProp: ', R.over(name, makeLower, band)); // name: "k.m.f.d.m"
    log('over compose: ', R.compose(R.view(name), R.over(name, makeLower))(band)); // name: "k.m.f.d.m"

    R.lensPath:

    const currentMemebers = R.lensPath(['members', 'current']);
    log('view path', R.view(currentMemebers, band))

    We can also combine two lens together:

    const name = R.lensProp('name');
    const currentMemebers = R.lensPath(['members', 'current']);
    //log('view path', R.view(currentMemebers, band))
    const makeLower = a => a.toLowerCase();
    // Use two lens together
    const lowerName = R.over(name, makeLower);
    const lowerMembers = R.over(currentMemebers, R.map(lowerName));
    console.log('new lower name', lowerMembers(band));

    R.lensIndex:

    const first = R.lensIndex(0)
    const getFistCurrentMember = R.compose(
        R.view(first),
        R.view(currentMemebers)
    )
    console.log(getFistCurrentMember(band)) // { name: 'Sascha Konictzko', plays: [ 'vocals', 'synth', 'guitar', 'bass' ] }

    Actually there is a better way to do this: by using R.compose(), one thing to notice is that, when working with lens, compose should go from left to right, instead of right to left. This is because how lens works in code.

    In our example:

    const band = {
        name: 'K.M.F.D.M',
        members: {
            current: [
                {name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
                {name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
                {name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
                {name: 'Steve While', plays: ['guitar']}
            ],
            past: [
                {name: 'Raymond Watts', plays: ['vocals', 'synth']},
                {name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
                {name: 'Gunter', plays: ['guitar', 'synth']}
            ]
        }
    };

    We should get 'members' first then 'current' first member:

    const currentMemebers = R.lensPath(['members', 'current']);
    const first = R.lensIndex(0)
    const firstCurrentMember = R.compose(
        currentMemebers, first
    )
    console.log(R.view(firstCurrentMember, band))

    You can think this is similar to Javascript Stack when using R.compose(lens1, len2).


    Example: 

    Using the same data from previous example:

    const band = {
        name: 'K.M.F.D.M',
        members: {
            current: [
                {name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
                {name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
                {name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
                {name: 'Steve While', plays: ['guitar']}
            ],
            past: [
                {name: 'Raymond Watts', plays: ['vocals', 'synth']},
                {name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
                {name: 'Gunter', plays: ['guitar', 'synth']}
            ]
        }
    };

    Requirements:

    /**
     * 1. Lowercase the name
     * 2. Omit the plays from the past
     * 3. Lowercase the current name
     * 4. Create 'all' under members combine 'current' & 'past'
     * 5. Pick get name and to lowercase for 'members.all'
     */

     Final results should be:

     /**
      * {
      "name": "k.m.f.d.m",
      "members": {
        "current": [
          {
            "name": "sascha konictzko",
            "plays": [
              "vocals",
              "synth",
              "guitar",
              "bass"
            ]
          },
          {
            "name": "lucia cifarelli",
            "plays": [
              "vocals",
              "synth"
            ]
          },
          {
            "name": "jules hodgson",
            "plays": [
              "guitar",
              "bass",
              "synth"
            ]
          },
          {
            "name": "steve while",
            "plays": [
              "guitar"
            ]
          }
        ],
        "past": [
          {
            "name": "Raymond Watts"
          },
          {
            "name": "En Esch"
          },
          {
            "name": "Gunter"
          }
        ],
        "all": [
          "sascha konictzko",
          "lucia cifarelli",
          "jules hodgson",
          "steve while",
          "raymond watts",
          "en esch",
          "gunter"
        ]
      }
    }
      */

     -----

    Answer:

    const R = require('ramda');
    
    const band = {
        name: 'K.M.F.D.M',
        members: {
            current: [
                {name: 'Sascha Konictzko', plays: ['vocals', 'synth', 'guitar', 'bass']},
                {name: 'Lucia Cifarelli', plays: ['vocals', 'synth']},
                {name: 'Jules Hodgson', plays: ['guitar', 'bass', 'synth']},
                {name: 'Steve While', plays: ['guitar']}
            ],
            past: [
                {name: 'Raymond Watts', plays: ['vocals', 'synth']},
                {name: 'En Esch', plays: ['vocals', 'drums', 'guitar', 'synth']},
                {name: 'Gunter', plays: ['guitar', 'synth']}
            ]
        }
    };
    
    /**
     * 1. Lowercase the name
     * 2. Omit the plays from the past
     * 3. Lowercase the current name
     */
     // makeLower :: s -> s
     const makeLower = s => s.toLowerCase();
     // lowerName :: obj a -> obj b
     const lowerName  = R.compose(makeLower, R.prop('name'));
     const name = R.lensProp('name');
     const pastMemebers = R.lensPath(['members', 'past']);
     const currentMemebers = R.lensPath(['members', 'current']);
    
     // Mapping over NAME lens, make string to lowercase
     const lowerBandName = R.over(
         name, makeLower
     );
     // Mapping over 'memebers.past' Lens, omit 'plays' prop
     const omitPastPlays = R.over(
         pastMemebers, R.map(R.omit(['plays']))
     );
     // Mapping over 'members.current' Lens, for each 'name' prop, make string to lowercase
     const lowerCurrentMemebersName = R.over(
         currentMemebers, R.map(
             R.over(name, makeLower)
         )
     );
    
     /**
      * 4. Create 'all' under members combine 'current' & 'past'
      * 5. Pick get name and to lowercase for 'members.all'
      */
     const allMemebers = R.lensPath(['members', 'all']);
     // lensConcat :: (Lens t, Lens s) -> a -> [b]
     const lensConcat = (targetLen, srcLen) => data =>
            R.over(targetLen, R.concat(R.view(srcLen, data)))(data);
    
    // A set of tranforms over prop 'members.all'
    // Set 'all' to []
    // concat 'past' to 'all'
    // concat 'current' to 'all'
    // pick name and conver to lowercase
    const createAllMembers = [
        R.over(allMemebers, R.map(lowerName)),
        lensConcat(allMemebers, currentMemebers),
        lensConcat(allMemebers, pastMemebers),
        R.set(allMemebers, [])
     ];
    
     const mods = [
        ...createAllMembers,
        lowerCurrentMemebersName,
        omitPastPlays,
        lowerBandName,
     ]
     const transform = R.compose(
        ...mods
     );
     const res = transform(band);
  • 相关阅读:
    【荐2】Total Commander 7.57 配置选项 个性化设置备份,,,开启时如何自动最大化???(二)
    【荐1】Total Commander 7.57 个人使用设置 及 常用快捷键 备忘
    Total Commander 集成、调用 Beyond Compare比较文件
    Linux/CentOS下开启MySQL远程连接,远程管理数据库
    如何查看、修改Linux的系统时间
    Linux cp (复制)命令简介
    Linux网络下载命令 wget 简介
    Linux如何下解压windows下的.zip和.rar文件
    Linux tar (打包.压缩.解压缩)命令说明 | tar如何解压文件到指定的目录?
    解决宿主机不能访问虚拟机CentOS中的站点 | 更新CentOS防火墙设置开启80端口访问
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10425203.html
Copyright © 2011-2022 走看看