[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
[].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的更多相关文章
- [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 ...
- [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 ...
- Functional Programming without Lambda - Part 2 Lifting, Functor, Monad
Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...
- 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 ...
- 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 ...
- Monad (functional programming)
In functional programming, a monad is a design pattern that defines how functions, actions, inputs, ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- Functional programming
In computer science, functional programming is a programming paradigm, a style of building the struc ...
- 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 ...
随机推荐
- CodeVS1380 没有上司的舞会 [树形DP]
题目传送门 没有上司的舞会 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个 ...
- Linux下c++常用调试
进程调试 自己写的代码,直接gdb r/bt就可以了. 正在运行的进程,先ps ax找到进程id.然后gdb进入之后attach 进程id.stop/continue暂停和继续进程. core了,有c ...
- 腾讯后台研发暑期实习offer经历
昨晚看到腾讯校招的微信状态,一颗心终于落下来了,终于可以去梦寐以求的鹅厂工作了.想想这一个多月以来,心情就像过山车一样,此起彼伏,一会充满希望,一会又跌入谷底. 三月份的时候,听说腾讯可以内推了,我内 ...
- vmware12安装centos7系统详解
1.首先需要准备的工具有vmware12和contos7的系统. vmvare12下载地址: http://pan.baidu.com/s/1i5vH50D contos7我自己使用的为1511版本. ...
- 埃及分数 a* 搜索 知识点mark
题意 在古埃及,人们使用单位分数的和(即1/a,a是自然数)表示一切有理 数. 例如,2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为在加数中不允许有相同的. 对于一个分数a/b,表示方法 ...
- [ZROI #316] ZYB玩字符串
Introduction 每次在一开始为空的串$S$的任意位置插入串$p$ 给出最终的$S$,求长度最短(相同时字典序最小)的串$p$ Solution: 样例出锅差评啊,让我这种直接看样例选手挂掉5 ...
- 【BZOJ】2131: 免费的馅饼
2131: 免费的馅饼 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 508 Solved: 310[Submit][Status][Discuss ...
- HDU 5641 King's Phone 模拟
King's Phone 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5641 Description In a military parade, ...
- POJ 1755 Triathlon (半平面交)
Triathlon Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4733 Accepted: 1166 Descrip ...
- Visual Studio技巧集锦
总结了一下VS的使用快捷键, 以下这些是必须转化为肌肉记忆的. 1.Ctrl+Shift+V循环粘贴不同的内容 剪贴板最多可以保存20项内容,通过Ctrl+Shift+V可以循环粘贴出之前复制过的内容 ...