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. bWAPP练习--injection篇SQL Injection (GET/Search)

    SQL注入: SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到 ...

  2. hdu 1058 dp.Humble Numbers

    Humble Numbers Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Subm ...

  3. django添加REST_FRAMEWORK 接口浏览

    1.安装rest_framework pip install djangorestframework  2.配置rest_framework ## 将rest_framework加入项目app列表 I ...

  4. Scrapy实战篇(六)之Scrapy配合Selenium爬取京东信息(上)

    在之前的一篇实战之中,我们已经爬取过京东商城的文胸数据,但是前面的那一篇其实是有一个缺陷的,不知道你看出来没有,下面就来详细的说明和解决这个缺陷. 我们在京东搜索页面输入关键字进行搜索的时候,页面的返 ...

  5. FastReport.Net使用:[18]形状(Shape)控件用法

    FastReport中,如果要画一张漂亮的报表,经常会画些形状控件来美化?那么如何用好形状(Shape)控件呢? 形状的5种类型 在工具栏的图形控件下拉菜单中有5种类型(矩形.圆角矩形.椭圆形.三角形 ...

  6. 用ExifInterface读取经纬度的时候遇到的一个问题

    如果读取图片经纬度,使用 String latValue = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE); String ln ...

  7. poj 2912 并查集(食物链加强版)

    题目:给出n个人玩剪刀石头布的游戏,其中有一个人是裁判,剩下的人分为3组,每一组的人只出某一种手型,裁判可以任意出.问是否能判断出哪个人是裁判 链接:点我 分分钟看吐血,先把食物链看懂吧 枚举裁判,然 ...

  8. hdu 4352 数位dp+nlogn的LIS

    题意:求区间L到R之间的数A满足A的的数位的最长递增序列的长度为K的数的个数. 链接:点我 该题的关键是记录LIS的状态,学习过nlogn解法的同学都知道,我们每次加入的元素要和前面的比对替换,这里就 ...

  9. 51..分治算法练习:  4378 【Laoguo】循环比赛

    时间限制: 1 s 空间限制: 1000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 设有n个选手进行循环比赛,其中n=2的m次方,要求每名选手要与其他n ...

  10. PHPredis长连接pconnect

    1. 当使用pconnect时,连接会被重用,连接的生命周期是fpm进程的生命周期,而非一次php的执行. 疑惑1: fpm进程的生命周期是指 当前那个还是指所有:    php-fpm通常是1个ma ...