In this lesson we'll take some existing code and refactor it using some functions from the Ramda library, most notably, compose
and converge
. When we're done, we'll have taken a function with a couple of local variables and parameter references and converted it into more streamlined "point-free" or "tacit" functions.
For example, we have following function:
const R = require('ramda'); const person = { id: 1, name: 'Joe' }; const generateUrl = (id) => `http://img.soicalnetwork.com/avatar/${id}.png`; const getUpdatedPerson = (person) => { const url = generateUrl(person.id); return R.assoc('avatar', url, person); } const result = getUpdatedPerson(person);
It will add a 'avatar' prop to person object.
We want to refactor the code to make it point free style, we the functions can be more reuseable and easy to understand.
First try:
//=============================================== // #1 Refactoring //=============================================== /* Solve the problem that when id is undefined, we need a default image Solution: propOr('defaultValue', 'prop') */ const generateUrl = (id) => `http://img.soicalnetwork.com/avatar/${id}.png`; const getUpdatedPerson = (person) => { const url = generateUrl(R.propOr('default', 'id')(person)); return R.assoc('avatar', url, person); } const result = getUpdatedPerson(person); console.log(result);
Here we use 'R.propOr', to get prop of an object and set default fallback value. This can help us prevent undefined problem.
Second try:
//=============================================== // #2 Refactoring //=============================================== /** * Extra a single function to get Person url. * Solution: Here we using R.compose. * SO getURLFromPerson is point-free function. */ const generateUrl = (id) => `http://img.soicalnetwork.com/avatar/${id}.png`; const getURLFromPerson = R.compose( generateUrl, R.propOr('default', 'id') ); const getUpdatedPerson = (person) => R.assoc('avatar', getURLFromPerson(person), person); const result = getUpdatedPerson(person); console.log(result);
Here we use 'R.compose' to make 'getURLFromPerson' as a point-free function. Notice in the function, we no longer need to pass 'person' object as a param.
Third try:
//=============================================== // #3 Refactoring //=============================================== /** * In getUpdatedPerson function, we still relay on the 'person' param we pass in. * We want to make it a point-free function also. * Solution: we can use R.converge */ const generateUrl = (id) => `http://img.soicalnetwork.com/avatar/${id}.png`; const getURLFromPerson = R.compose( generateUrl, R.propOr('default', 'id') ); // const getUpdatedPerson = (person) => R.assoc('avatar', getURLFromPerson(person), person); const getUpdatedPerson = R.converge( R.assoc('avatar'), [ getURLFromPerson, R.identity ] ) const result = getUpdatedPerson(person); console.log(result);
The old verson of 'getUpdatedPerson' relay on 'person' param, to make it as point-free function style, we can use another way 'R.converge'.