-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Week4-solution-task1-task7 #1
base: master
Are you sure you want to change the base?
Conversation
week4/solutions.js
Outdated
R.prepend(R.__, task7_scores), | ||
R.objOf("score"), | ||
a => +a | ||
)(task7_payload); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May need to pass task7_payload. payloadString
instead of task7_payload
? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ye
{ id: 2, score: 40 }, | ||
{ id: 3, score: 80 } | ||
]; | ||
R.adjust( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More tacit, less performant approach.
const mapper = predict => when(
propSatisfies(predict, 'id'),
evolve({
score: add(10)
})
);
compose(map(
mapper(
equals(2)
)
))(task2_data);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice effort. See if we can understand the function as applicative functor
{ id: 2, score: 40 }, | ||
{ id: 3, score: 80 } | ||
]; | ||
R.adjust( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a combinator called S combinator:
const S = f => g => x => f(x)(g(x))
If we write the following 2 utility functions first,
const findIdEq = id => R.findIndex(R.propEq("id", id))
const adjustScore = data => index => R.adjust(
R.evolve({
score: R.add(10)
}),
index
)(data)
Then we can apply the S combinator:
S(adjustScore)(findIdEq(2))(task2_data) // [{"id": 1, "score": 90}, {"id": 2, "score": 50}, {"id": 3, "score": 80}]
Further more, since function
itself is an Applicative functor, meaning curried function is a functor contains a function, we can rewrite the above using ramda's ap
function (which treat function as Applicatives):
ap(adjustScore)(findIdEq(2))(task2_data) // [{"id": 1, "score": 90}, {"id": 2, "score": 50}, {"id": 3, "score": 80}]
Understanding the above provides great intuition about Applicative Functor. Please take your time and ask any questions you like.
Suggested reading:
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html#applicatives
The book mentioned in this wiki link
fantasyland combinators
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow. 👍 will check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the detailed explanation.
What's the intuition behind the ramda ap using s combinator.
Are there any recommended chapters in to mock a mockingbird?
Also it was mentioned function
is an Applicative functor,
not getting much why from here , is it a ramda thing or is there any type related theorem behind that?
ramda/ramda#2174
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@exiadbq
First, to mock a mocking bird covers a fair amount of combinator logic. it deserves a cover to cover read. But don't expect it's an easy read. It needs multiple attempts from experience.
For all other questions, I need to start with the type for any function:
a -> b
It is a Functor, if we treat a ->
as a container. (it is also a contravariant functor but not a concern here). To make it a functor, we need to implement map
function for it. Let's start with the type signature for map
:
Functor f => (c -> d) -> f c -> f d
If we substitute f
out with a ->
, we have:
(c -> d) -> (a -> c) -> (a -> d)
Then hopefully, the implementation for the above type is obvious now. It is composing c -> d
after a -> c
. It also needs to satisfy functor law. But I'll leave that out for this explanation :)
The next step is to see if we can make a ->
an applicative.
To make an applicative, we need to implement ap
function. Let's again start with the type signature for ap
:
Functor f => f (c -> d) -> f c -> f d
Again, by substitute f
out with a ->
, we'll have:
(a -> (c -> d)) -> (a -> c) -> (a -> d)
The above function take a parameter (a -> (c -> d))
(we'll name it as f
), other parameter (a -> c)
(we'll name it as g
) and to get the return value (a -> d)
, we need to do the following:
- call
f
with a value of typea
. That will give us a function of type(c -> d)
- call
g
with a value of typea
. That will give us a value of typec
- call the function we get from step 1 (
c -> d
) with the value from step 2 (c
), we'll have a value of typed
. In other words,f(x)( g(x) )
has typed
, wherex
is of typea
- So to write out the implementation for function type
(a -> d)
, it isx => f(x)( g(x) )
x => f(x)( g(x) )
is exactly the same as S combinator or Starling Bird if you prefer bird names :D
So, it is not a ramda specific thing. Function by nature is an applicative functor, ramda's ap
function just treat any function as an applicative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @alexi21 @Hyunkim95 . I like to share the above with you guys.
I think the above is beneficial given Eventhub's code base is highly functional.
week4/solutions.js
Outdated
output: [<div key="name">John</div>, <div key="age">20</div>] | ||
############################################################################ */ | ||
var transforma = (num, key, obj) => "<div key=" + "key" + ">" + num + "</div>"; | ||
R.values(R.mapObjIndexed(transforma, { name: "John", age: 20 })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing like the following as a habit so that you always create a function that can be composed later on.
const format = compose(
R.values,
R.mapObjIndexed(transforma)
)
format({ name: "John", age: 20 })
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
week4/solutions.js
Outdated
const activities = [{ taskId: 6441 }, { taskId: 289 }]; | ||
|
||
const findBytaskId = data => id => { | ||
return R.compose( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need to use curly brackets and return here.
week4/solutions.js
Outdated
}; | ||
|
||
console.log( | ||
R.compose( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need for compose to be here
week4/solutions.js
Outdated
input: const n = 2 | ||
output: [{score: 2}, {score: 1}] | ||
############################################################################ */ | ||
const f = n => (n <= 0 ? false : [R.objOf("score")(n), n - 1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compose(
reverse,
addIndex(map)((v, i)=> ({score: i+1})),
repeat(1))
(2)
I reckon your one is better.
output: {'/factory/1/noise': [], '/factory/1/temperature': []} | ||
############################################################################ */ | ||
|
||
R.zipObj(R.values(input), R.repeat([], 2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compose(
map(objOf(__, [])),
values)
output: | ||
{showDialog: false, buttonDisabled: false, slides: [{id: 1, name: 'programming'}]} | ||
############################################################################ */ | ||
// skip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did you skip this one?
const l = {showDialog: false, buttonDisabled: false, slides: []}
const r = {showDialog: true, buttonDisabled: true, slides: [{id: 1, name: 'programming'}]}
const concatValues = (k, l, r) => typeof l === 'boolean' ? l && r : concat(l, r)
mergeWithKey(concatValues, l, r)
seems a monoid example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@exiadbq We feel the use case is a bit weird.
week4/solutions.js
Outdated
// const airQualitySensorData = {airQuality: 40} | ||
// produce: | ||
// {noise: 20, temperature: 30, airQuality: 40} | ||
R.evolve({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const input11 = {connecting: true, connected: false}
mapObjIndexed(not)(input11)
@shineli1984 @ttma1046 @ddvkid @stevemao