How to make it point-free when there is local variable?

80 Views Asked by At

I have a code snippet to remove the host part from server URL in OpenAPI definition. I don't know how to make it point-free totally. (It isn't necessary to do that. But I just want to know how to.)

The difficult part to me is to get rid of the local variable idx. I read this SO and it seems that ap can solve. I didn't try because there is no ap in lodash.

const convert = _.flow([
  _.split('/'),
  (segments) => {
    const idx = _.findLastIndex(containAny(['{', '}', ':']))(segments);
    return _.drop(idx+1, segments);
  },
  _.reject(_.isEmpty),
  _.join('/'),
  path => '/' + path,
]);

Full code:

const _ = require('lodash/fp');

const urls = [
  'http://localhost:8080/petstore/v1',
  '//localhost/petstore/v1',
  '{server}/batch-service/api/batches/lwm2m/v1',
  'https://{server}/batch-service/api/batches/lwm2m/v1',
  '/batch-service/api/batches/lwm2m/v1',
  '/',
]

const containAny = patterns => str => _.some(pattern => _.includes(pattern, str), patterns);

const convert = _.flow([
  _.split('/'),
  (segments) => {
    const idx = _.findLastIndex(containAny(['{', '}', ':']))(segments);
    return _.drop(idx+1, segments);
  },
  _.reject(_.isEmpty),
  _.join('/'),
  path => '/' + path,
]);

_.map(convert)(urls);
2

There are 2 best solutions below

0
Ori Drori On BEST ANSWER

In your case you need to call _.findLastIndex() on segments, and then call _.drop() on the results of the find and segments:

drop(findLastIndex(segments))(segments)

Which is equivalent to the chain combinator function:

const chain = f => g => x => f(g(x))(x);

Lodash/fp accepts all functions when using _.flow() (which is also a functional combinator), so you can create other functional combinators, and use them.

const chain = f => g => x => f(g(x))(x);

const containAny = patterns => str => _.some(pattern => _.includes(pattern, str), patterns);

const findLastSegmentIndex = _.flow(
  _.findLastIndex(containAny(['{', '}', ':'])),
  _.add(1)
)

const convert = _.flow([
  _.split('/'),
  chain(_.drop)(findLastSegmentIndex),
  _.reject(_.isEmpty),
  _.join('/'),
  path => '/' + path,
]);

const urls = [
  'http://localhost:8080/petstore/v1',
  '//localhost/petstore/v1',
  '{server}/batch-service/api/batches/lwm2m/v1',
  'https://{server}/batch-service/api/batches/lwm2m/v1',
  '/batch-service/api/batches/lwm2m/v1',
  '/',
];

const result = _.map(convert)(urls);

console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

1
Markus On

You'd need converge, which lodash doesn't have, but Ramda has. It applies different functions to the same argument and then uses the result of these applications as arguments for another given function.

const convert = _.flow([
  _.split('/'),
  R.converge(_.drop, [_.flow([_.findLastIndex(containAny(['{', '}', ':'])), add(1)]), _.identity]),
  _.reject(_.isEmpty),
  _.join('/'),
  path => '/' + path,
]);

https://ramdajs.com/docs/#converge