I'm learning Ramda
and I'm a little confused how to build this lodash
chain below using Ramda
. Ramda
returns functions for it's operations instead of actual values, and this seems to be the focal point of functional programming, however in this example I have a second parameter localRegex
that isn't a primary argument. It seems that it wouldn't be possible to get this to be completely duplicated without wrapping the Ramda
function and using .apply()
or .call()
to propagate the wrapped function arguments to the Ramda
function, which seems more complicated then using lodash
.
var _ = require("lodash")
var R = require("ramda")
var localRegex = /^.\.\/|^.\/|^\//
function getRecursiveDeps(deps, localRegex){
return _.chain(deps)
.map(function(dep){
return dep.source.value
})
.filter(function(dep){
return dep.match(localRegex)
})
.value()
}
var items = [
{
"source": {
"value": "./foo"
}
},
{
"source": {
"value": "bar"
}
}
]
console.log(getRecursiveDeps(items, localRegex))
Here's what I've got and its not working.
var getRecursiveDeps = R.chain(
R.map(function(dependency){
return dependency.source.value
}),
R.filter(function(value){
return value.match(localRegex)
})
)
Is there a way to have Ramda
use a main variable for chaining and also pass down localRegex
? Is there a way to duplicate the getRecursiveDeps
that uses lodash
in Ramda
?
There's a lot of talk about how Ramda
is functional and underscore
and lodash
aren't. But in this case the getRecursiveDeps
is a function that returns a value from lodash
. When you create functions like this from lodash
or underscore
the result is the same, there's just more work when it comes to wrapping it, in this case what would be the perk using Ramda
over Lodash
?
R.chain
does something completely different from _.chain
. Its type, according to the current documentation, is (a -> [b]) -> [a] -> [b]
, though its actual type is more general. Think of it as a "flat-map" function.
What you actually want here is R.compose
or its left-to-right equivalent R.pipe
.
If the goal of the function is to find local dependencies, it seems appropriate to me to embed the pattern in the function. I would thus write:
// getLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalDeps =
R.pipe(R.map(R.path(['source', 'value'])),
R.filter(R.test(/^[.]{0,2}[/]/)));
getLocalDeps(items); // => ['./foo']
I'm a bit confused by the name getRecursiveDeps
as the function isn't recursive. getLocalDeps
seems more appropriate.
If you'd like to parameterize the pattern, I suggest breaking getLocalDeps
into smaller pieces:
// isLocal :: String -> Boolean
const isLocal = R.test(/^[.]{0,2}[/]/);
// getDeps :: [{ source :: { value :: String }}] -> [String]
const getDeps = R.map(R.path(['source', 'value']));
// getLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalDeps = R.pipe(getDeps, R.filter(isLocal));
You could then define other functions in terms of these building blocks:
// getNonLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getNonLocalDeps = R.pipe(getDeps, R.reject(isLocal));
// getLocalJsonDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalJsonDeps = R.pipe(getLocalDeps, R.filter(R.test(/[.]json$/)));