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. 洛谷P1073 最优贸易 [图论,DP]

    题目传送门 最优贸易 题目描述 C 国有n 个大城市和m 条道路,每条道路连接这n 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这m 条道路中有一部分为单向通行的道路,一部分为双向 ...

  2. 记录一下最近犯得sb的翻车错误

    首先是: 数据范围是long long范围,然后写了一个暴力,觉得过不去,于是开了int范围,最后写了个能骗过所有数据的骗分,然后没开longlong... 接着是: for(int i = l; i ...

  3. SpringBoot学习(五)

    package org.springboot.sample.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; impor ...

  4. CF617/E XOR and Favorite Number

    题目链接:http://codeforces.com/contest/617/problem/E 题意:给出一个长度为n(1e5)的序列,有m(1e5)次操作,每次操作选择一个L-R区间,然后输出符合 ...

  5. luoguP4206 [NOI2005]聪聪与可可 期望概率DP

    首先,分析一下这个猫和鼠 猫每局都可以追老鼠一步或者两步,但是除了最后的一步,肯定走两步快些.... 既然猫走的步数总是比老鼠多,那么它们的距离在逐渐缩小(如果这题只能走一步反而不能做了...) 猫不 ...

  6. HDU3853 LOOPS 期望DP 简单

    http://acm.hdu.edu.cn/showproblem.php?pid=3853 有一点坑的地方是如果一个地方停在原地的概率为1,那么该地的期望为0,就相当于这个地方也是一个出口...   ...

  7. Navicat连接Docker中的mysql报错:client does not support authentication

    1.进入mysql容器中 docker exec -it mysqltest(mysql容器名称) bash 2.进入mysql数据库 mysql -uroot -p 3.输入mysql密码 4.远程 ...

  8. 【8.30校内测试】【找规律模拟】【DP】【二分+贪心】

    对于和规律或者数学有关的题真的束手无策啊QAQ 首先发现两个性质: 1.不管中间怎么碰撞,所有蚂蚁的相对位置不会改变,即后面的蚂蚁不会超过前面的蚂蚁或者落后更后面的蚂蚁. 2.因为所有蚂蚁速度一样,不 ...

  9. bzoj 2055: 80人环游世界 -- 上下界网络流

    2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description     想必大家都看过成龙大哥的<80天环游世界>,里面 ...

  10. Apache -- XAMPP Apache 无法启动原因及解决方法

    XAMPP Apache 无法启动原因1(缺少VC运行库): 这个就是我遇到的问题原因,下载安装的XAMPP版本是xampp-win32-1.7.7-VC9,而现有的Windows XP系统又没有安装 ...