Hi,
I am trying to use composeK but I got some error.
Here is my code
const studentList = [{
name: 'dOg',
nickname: ' goofY ',
score: {
js: 7,
html: 8,
css: 9,
},
}, {
name: ' caT ',
nickname: 'tom',
score: {
js: 6,
html: 7,
css: 8,
},
}, {
name: 'MOUSE',
nickname: ' jerry',
score: {
js: 8,
html: 9,
css: 10,
},
}];
const getScore = R.prop('score');
const getJs = R.prop('js');
const getJsScore = R.composeK(getJs, getScore);
getJsScore(studentList); // -> [7, 6, 8]
Online link is here
When I tried to run those code, I got an error message Cannot read property 'fantasy-land/chain' of undefined
I don't know is my code have any problem or composeK is broken.
Can any give me some help?
Hi @MengWeiChen,
We can take a look at the type signatures in play here to see what is going on with your code. An explanation of the type signatures is available here. composeK has a fairly restrictive type signature, so it isn't used all that often in my experience.
composeK :: Chain m => ((b -> m c), (a -> m b)) -> (a -> m c)
studentList :: Array Object
getScore :: Object -> Object
getJs :: Object -> Number
Because Array sarisfies the type constraint, it can be used as the m in Chain m, however, none of the functions you're composing _return_ a Chain which is the requirement for using composeK. In fact, in this case, you'll want to use map to appy a function to a list of values.
map :: Functor f :: (a -> b) -> f a -> f b
Once we replace Functor f with Array we get (a -> b) -> Array a -> Array b.
All type signatures aside, if you are looking at running a function over a list of values, you're almost always going to want to use map.
We can then use a regular compose for our two prop calls:
const getJsScore = compose(getJs, getScore);
So the final function could be used like this:
map(getJsScore, studentList) Link
Lastly, Ramda has a function called path which will simplify your mapping function. Instead of compose(getJs, getScore) you can just do path(['score', 'js']) so the final solution would be:
map(path(['score', 'js']), studentList) //[7, 6, 8].
Please let me know if that's helpful at all. In addition to asking questions here, we also have a chat room that's very active, and you'll find a lot of helpful people in there.
Most helpful comment
Hi @MengWeiChen,
We can take a look at the type signatures in play here to see what is going on with your code. An explanation of the type signatures is available here.
composeKhas a fairly restrictive type signature, so it isn't used all that often in my experience.composeK :: Chain m => ((b -> m c), (a -> m b)) -> (a -> m c)studentList :: Array ObjectgetScore :: Object -> ObjectgetJs :: Object -> NumberBecause
Arraysarisfies the type constraint, it can be used as theminChain m, however, none of the functions you're composing _return_ aChainwhich is the requirement for usingcomposeK. In fact, in this case, you'll want to usemapto appy a function to a list of values.map :: Functor f :: (a -> b) -> f a -> f bOnce we replace
Functor fwithArraywe get(a -> b) -> Array a -> Array b.All type signatures aside, if you are looking at running a function over a list of values, you're almost always going to want to use
map.We can then use a regular
composefor our twopropcalls:const getJsScore = compose(getJs, getScore);So the final function could be used like this:
map(getJsScore, studentList)LinkLastly, Ramda has a function called
pathwhich will simplify your mapping function. Instead ofcompose(getJs, getScore)you can just dopath(['score', 'js'])so the final solution would be:map(path(['score', 'js']), studentList) //[7, 6, 8].Please let me know if that's helpful at all. In addition to asking questions here, we also have a chat room that's very active, and you'll find a lot of helpful people in there.