zoukankan      html  css  js  c++  java
  • [Functional Programming] Write simple Semigroups type

    An introduction to concatting items via the formal Semi-group interface. Semi-groups are simply a type with a concat method that are associative. We define three semigroup instances and see them in action.

    1. What is Semigroups:

    Array type, String type, they are semigroup, because both has ´concat´ method:

    "a".concat("b").concat("c"); // abc
    [1].concat([2]).concat([3]); //[1,2,3]

    Sum:

    But Number type is not semigroup, because you cannot concat two number... well, for now...

    Not let's define a Semigroup for Number as well, it is called 'Sum':

    // Sum :: Sum s => a -> s a
    const Sum = x => ({
        x,
        concat: ({x: y}) => Sum(x + y),
        inspect: () => `Sum ${x}`
    })

    Sum takes a variable 'a' and return Sum(a). Here 'a' should be number type. We export 'x' to outside world from Sum is for easy accessing the value from Another Sum.

    const res1 = Sum(11).concat(Sum(12)).concat(Sum(2));
    console.log(res1); // Sum 25

    All / Any:

    Boolean in JS is not a semigroup type, we can make it so by introduces 'All & Any' semigroup type:

    // All :: All s => b -> s b
    const All = x => ({
        x,
        concat: ({x: y}) => All(y && x),
        inspect: () => `All ${x}`
    });
    // Any :: Any s => b -> s b
    const Any = x => ({
        x,
        concat: ({x: y}) => Any( y || x),
        inspect: () => `Any ${x}`
    })
    const res2 = All(false).concat(All(true));
    const res23 = Any(false).concat(Any(true));
    console.log(res2) // All false
    console.log(res3) // Any true

    First:

    Wcan define a semigroup type for any other Object in JS, which only return the First one, ignore the rest:

    // First :: First f => a -> f a
    const First = x => ({
        x,
        concat: (_) => First(x),
        inspect: () => `First ${x}`
    })
    
    const res3 = First('a').concat(First(2)).concat(First(2));
    console.log(res3) // 'a'

    Map:

    Object in JS don't have 'concat' method, of course you can use some libs such as https://github.com/DrBoolean/immutable-ext

    But here, we will define a simple version of Map by ourselves. Which loop though each props of the given object, apply concat method for each prop:

    // Map :: Map m => a -> m a
    const Map = x => ({
        x,
        concat: ({x: y}) => Object.keys(y).map(k => y[k].concat(x[k]))
    });

    Let take a example to see how those semigroup types can be useful:

    For example we have to object, we want to 'concat' them, by concat, I mean, for the name prop, we just want to keep the First one, for the 'isPaid' prop we want to take 'All' operation, for 'points' we want to take 'Sum' operation, for 'friends', you guess so... 'concat' operation.

    const _acct1 = {name: 'Nico', isPaid: true, points: 10, friends: ['Franklin']};
    const _acct2 = {name: 'Nico', isPaid: false, points: 30, friends: ['Gatsby']};

    So the final result should be:

    // [ Nico, false, 40, [ 'Gatsby', 'Franklin' ] ]

    First, let's apply the Semigroup types we already have to those two objects:

    const acct1 = {name: First('Nico'), isPaid: All(true), points: Sum(10), friends: ['Franklin']};
    const acct2 = {name: First('Nico'), isPaid: All(false), points: Sum(30), friends: ['Gatsby']};

    OK, now we need to concat 'acct1' and 'acct2', but Object doesn't have 'concat' method as we discussed before, therefore we need to wrap our objects into 'Map':

    const acct1 = Map({name: First('Nico'), isPaid: All(true), points: Sum(10), friends: ['Franklin']});
    const acct2 = Map({name: First('Nico'), isPaid: All(false), points: Sum(30), friends: ['Gatsby']});

    Now we can call:

    const res4 = acct1.concat(acct2);
    console.log(res4); // [ First Nico, All false, Sum 40, [ 'Gatsby', 'Franklin' ] ]

    OK, that's it. The end of Semigroup... 

    Below I append a better version:

    const R = require('ramda');
    
    // Sum :: Sum s => a -> s a
    const Sum = x => ({
        x,
        concat: ({x: y}) => Sum(x + y),
        inspect: () => `Sum ${x}`
    })
    const res1 = Sum(11).concat(Sum(12)).concat(Sum(2));
    console.log(res1); // {x: 25}
    
    // All :: All s => b -> s b
    const All = x => ({
        x,
        concat: ({x: y}) => All(y && x),
        inspect: () => `All ${x}`
    });
    // Any :: Any s => b -> s b
    const Any = x => ({
        x,
        concat: ({x: y}) => Any( y || x),
        inspect: () => `Any ${x}`
    })
    const res2 = All(false).concat(All(true));
    console.log(res2) // All false
    
    // First :: First f => a -> f a
    const First = x => ({
        x,
        concat: (_) => First(x),
        inspect: () => `First ${x}`
    })
    
    const res3 = First('a').concat(First(2)).concat(First(2));
    console.log(res3) // 'a'
    
    
    const _acct1 = {name: 'Nico', isPaid: true, points: 10, friends: ['Franklin']};
    const _acct2 = {name: 'Nico', isPaid: false, points: 30, friends: ['Gatsby']};
    
    // Map :: Map m => a -> m a
    const Map = x => ({
        x,
        concat: ({x: y}) => Object.keys(y).map(k => y[k].concat(x[k]))
    });
    const transformations = R.evolve({
        name: First,
        isPaid: All,
        points: Sum
    });
    const semi_transform = R.compose(
        Map,
        transformations
    );
    const acct1 = semi_transform(_acct1);
    const acct2 = semi_transform(_acct2);
    const res4 = acct1.concat(acct2);
    console.log(res4); // [ First Nico, All false, Sum 40, [ 'Gatsby', 'Franklin' ] ]
  • 相关阅读:
    ACM/ICPC 之 一道不太简单的DP面试题(Geeksforgeeks)
    ACM/ICPC 之 简单DP-记忆化搜索与递推(POJ1088-滑雪)
    ACM/ICPC 之 递归(POJ2663-完全覆盖+POJ1057(百练2775)-旧式文件结构图)
    ACM/ICPC 之 枚举(POJ1681-画家问题+POJ1166-拨钟问题+POJ1054-讨厌的青蛙)
    JAVA手记 JAVA入门(安装+Dos下运行)
    ACM/ICPC 之 BFS(离线)+康拓展开(TSH OJ-玩具(Toy))
    ACM/ICPC 之 优先级队列+设置IO缓存区(TSH OJ-Schedule(任务调度))
    ACM/ICPC 之 BFS(离线)+康拓展开 (HDU1430-魔板)
    JAVA中的数据结构——集合类(序):枚举器、拷贝、集合类的排序
    JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口<HashMap类、TreeMap类>)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10419571.html
Copyright © 2011-2022 走看看