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. Python-函数总结

    把程序分解成较小的部分,主要有3种方法. 函数(function) 对象(object) 模块(module) 本节我们先学习函数.函数是带名字的代码块,可以把多个逻辑封装起来.这样就可以在程序中可以 ...

  2. Python 函数系列- Str

    Str函数的一些有趣的用法 str = '1234567890' print(str[:]) #取全部字符串 print(str[2]) #取下标是2的字符 -- 3 print(str[:3]) # ...

  3. IntelliJ 、Pycharm、webstorm 2017 注册码及注册服务器

    jetbrains 家的东西都非常好看,但是价格贵的令人发指,所以我搭建了一个 Pycharm激活服务器,可以用来激活 Pycharm,IntelliJ IDEA,WebStorm.避免频繁更换激活码 ...

  4. Spring Boot 整合MyBatis(1)

    这篇文章介绍如何在Spring boot中整合Mybatis,其中sql语句采用注解的方式插入.后续文章将会介绍,如何使用xml方式. SSM SSH框架已经满足轻量级这个需求了,但是对于开发人员而言 ...

  5. CF438 The Child and Sequence

    题意: 给定一个长度为n的非负整数序列a,你需要支持以下操作:1)给定l,r,输出a[l] + a[l+1] + ... + a[r] 2)给定l,r,x, 将a[l].a[l+1]......a[r ...

  6. Redis学习篇(五)之Set类型及其操作

    SADD 作用:向集合中添加元素 语法:SADD key menber [, ...] 添加重复的元素会返回0,失败 SMEMBERS 作用:返回指定集合中的元素 语法: SMEMBERS key S ...

  7. FastReport.Net使用:[16]图片控件使用

    FastReport中,图片(Picture)控件的用法? 支持的图片格式 1.BMP, PNG, JPG, GIF, TIFF, ICO, EMF, WMF 支持的数据源 支持图片,数据列,文件名, ...

  8. java 安全 技术

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 加密对应的类 是 Cipher ,意思 是加密的意思.这个类 在  javax.cryp ...

  9. BZOJ1073 k短路(A*算法)

    A*算法,也叫启发式搜索,就是设计一个预估函数,然后在搜索的过程中进行有序的搜索,我们设到目前状态的花费为f(x),到目标状态的估计花费为h(x),那么我们按照h(x)+f(x)排序即可,这道题里起点 ...

  10. 51nod2000 四边形分割平面 规律题

    观察样例,$ans(1) = 1, ans(2) = 10$,再手推一组,$ans(3) = 26$ 可以发现规律$ans(n) = (2n - 1)^2 + 1$ 如果还是没看出规律,那么打个程序去 ...