Ramda
--- ### What's Ramda
A Functional Programming Libraries in JavaScript
-
Designed in pure function style
-
Immutable structures
-
Functions are automatically curried
Purity
A function is pure if the return value is only determined by its input values,
and does not produce side effects.
const greet = (name) => 'Hello, ' + name
greet('Tracy') // 'Hello, Tracy'
Immutability
The function creates a copy of the structure instead of changes.
const arr1 =[1,2,3];
arr1.push(4);
arr1.push(5);
console.log(arr1); // [1, 2, 3, 4, 5]
var arr2 = [1, 2, 3];
console.log(R.append(4, arr2)); // [1, 2, 3, 4]
console.log(R.append(5, arr2)); // [1, 2, 3, 5]
Currying
A function with multiple arguments is transformed to a function with a single argument
returning another function with a single argument
const add = (a, b) => a + b;
const curriedAdd = (x) => (y) => x + y;
curriedAdd(10)(5) // 15
const add2 = curriedAdd(2) // (b) => 2 + b
add2(10) // 12
Why Curry
- Function can be partially configure
- Function are resue
const object = [{ id: 1 }, { id: 2 }, { id: 3 }];
object.map(function(o){
return o.id;
});
const get = R.curry(function(property, object){
return object[property];
});
object.map(get('id')) //= [1, 2, 3]
Installation
$ npm install ramda
import R from 'ramda';
or from a CDN
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
Type Signatures
Type Signatures (cont.)
-
Named Types: String, Number, Boolean ...
-
List of Values: [Number], [String] ...
-
Functions: (Number -> Number), (String -> [String]) ...
// findWords :: String -> [String]
const findWords = sentence => sentence.split(/\s+/);
findWords('She sells seashells by the seashore');
//=> ["She", "sells", "seashells", "by", "the", "seashore"]
Type Signatures (cont.)
- Currying: Number → Number → Number
// calculateTax :: Number -> Number -> Number
const calculateTax = R.curry((rate, base)
=> Math.round(100 * base + base * rate) / 100);
- Type Variables : (a -> b) -> [a] -> [b]
// map :: (String -> Number) -> [String] -> [Number]
map(word => word.length, ['Four', 'score', 'and', 'seven']);
//=> [4, 5, 3, 5]
// map :: (Number -> Number) -> [Number] -> [Number]
map(n => n * n, [1, 2, 3, 4, 5]);
//=> [1, 4, 9, 16, 25]
// map :: (a -> b) -> [a] -> [b]
Let's buld a todo list
Todo list: list incomplete tasks
const incomplete = function(arr) {
const tamp = [];
arr.map((obj)=>{
if(obj.complete === false){
tamp.push(obj);
}
});
return tamp;
}
console.log(incomplete(tasks));
Todo list: list incomplete tasks
const incomplete = function(arr) {
const tamp = [];
arr.map((obj)=>{
if(obj.complete === false){
tamp.push(obj);
}
});
return tamp;
}
console.log(incomplete(tasks));
writing in ramda
const incomplete = R.filter(R.whereEq({complete: false}));
console.log(incomplete(tasks));
Todo list: list the tasks that active by user
const groupBy = function ( array , f ) {
const groups = {};
array.forEach((o)=>{
const group = JSON.stringify(f(o));
groups[group] = groups[group] || [];
groups[group].push( o );
});
return Object.keys(groups).map(( group )=>{
return groups[group];
})
}
console.log(groupBy(incomplete(tasks) , (obj) => [obj.username]));
Todo list: list the tasks that active by user
const groupBy = function ( array , f ) {
const groups = {};
array.forEach((o)=>{
const group = JSON.stringify(f(o));
groups[group] = groups[group] || [];
groups[group].push( o );
});
return Object.keys(groups).map(( group )=>{
return groups[group];
})
}
console.log(groupBy(incomplete(tasks) , (obj) => [obj.username]));
writing in ramda
const groupByUser = R.groupBy(R.prop('username'));
const activeByUser = R.compose(groupByUser, incomplete);
console.log(activeByUser(tasks));
DEMO
--