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
[].concat([]).concat([]); //[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().concat(Sum()).concat(Sum());
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()).concat(First());
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: , friends: ['Franklin']};
const _acct2 = {name: 'Nico', isPaid: false, points: , 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(), friends: ['Franklin']};
const acct2 = {name: First('Nico'), isPaid: All(false), points: Sum(), 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(), friends: ['Franklin']});
const acct2 = Map({name: First('Nico'), isPaid: All(false), points: Sum(), 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().concat(Sum()).concat(Sum());
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()).concat(First());
console.log(res3) // 'a' const _acct1 = {name: 'Nico', isPaid: true, points: , friends: ['Franklin']};
const _acct2 = {name: 'Nico', isPaid: false, points: , 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' ] ]

[Functional Programming] Write simple Semigroups type的更多相关文章

  1. [Functional Programming] From simple implementation to Currying to Partial Application

    Let's say we want to write a most simple implementation 'avg' function: const avg = list => { let ...

  2. [Functional Programming] Compose Simple State ADT Transitions into One Complex Transaction

    State is a lazy datatype and as such we can combine many simple transitions into one very complex on ...

  3. Functional Programming without Lambda - Part 2 Lifting, Functor, Monad

    Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...

  4. Functional Programming without Lambda - Part 1 Functional Composition

    Functions in Java Prior to the introduction of Lambda Expressions feature in version 8, Java had lon ...

  5. a primary example for Functional programming in javascript

    background In pursuit of a real-world application, let’s say we need an e-commerce web applicationfo ...

  6. Monad (functional programming)

    In functional programming, a monad is a design pattern that defines how functions, actions, inputs, ...

  7. Beginning Scala study note(4) Functional Programming in Scala

    1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...

  8. Functional programming

    In computer science, functional programming is a programming paradigm, a style of building the struc ...

  9. BETTER SUPPORT FOR FUNCTIONAL PROGRAMMING IN ANGULAR 2

    In this blog post I will talk about the changes coming in Angular 2 that will improve its support fo ...

随机推荐

  1. 洛谷P1099 BZOJ1999 树网的核 [搜索,树的直径]

    洛谷传送门,BZOJ传送门 树网的核 Description 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenetwork),其中V ...

  2. 【Python初级】由判定回文数想到的,关于深浅复制,以及字符串反转的问题

    尝试用Python实现可以说是一个很经典的问题,判断回文数. 让我们再来看看回文数是怎么定义的: 回数是指从左向右读和从右向左读都是一样的数,例如1,121,909,666等 解决这个问题的思路,可以 ...

  3. zimg 启动命令

    cd zimgcd bin ./zimg conf/zimg.lua

  4. Python Socket多线程并发

    1.SocketServer模块编写的TCP服务器端代码 Socketserver原理图 服务端: import SocketServer #导入SocketServer,多线程并发由此类实现 cla ...

  5. 【BZOJ 3527】 3527: [Zjoi2014]力 (FFT)

    3527: [Zjoi2014]力 Time Limit: 30 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2003  Solved: 11 ...

  6. 【BZOJ 1062】 1062: [NOI2008]糖果雨 (二维树状数组)**

    1062: [NOI2008]糖果雨 Description 有一个美丽的童话:在天空的尽头有一个" 糖果国" ,这里大到摩天大厦,小到小花小草都是用糖果建造而成的.更加神奇的是, ...

  7. [SPOJ SEQN] [hdu3439]Sequence

    题目就是求C(n,k)*H(n - k)%m 0<= k<= n <=10^9, 1 <= m <= 10^5, n != 0 其中H(n)是错排第n项. 对于C(n,k ...

  8. [BZOJ1791][IOI2008]Island岛屿(环套树DP)

    同NOI2013快餐店(NOI出原题?),下面代码由于BZOJ栈空间过小会RE. 大致是对每个连通块找到环,在所有内向树做一遍DP,再在环上做两遍前缀和优化的DP. #include<cstdi ...

  9. 没有调用PageHelper.startPage()分页方法,最后还是执行了PageHelper分页方法的原因

    SELECT * FROM ( SELECT TMP_PAGE.*, ROWNUM ROW_ID FROM ( SELECT * FROM ( SELECT A.*, ROWNUM RN FROM ( ...

  10. [转]Android Studio开发入门-引用jar及so文件

    注意: 1.jar包在app的libs目录 2.so文件放在src/main”目录中名为“jniLibs”的目录 一.引用jar文件    1.将jar文件复制.粘贴到app的libs目录中:    ...