-
Notifications
You must be signed in to change notification settings - Fork 21
Add monoid instances for uncurried EffectFn
s
#13
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
Conversation
EffectFn
s
999def0
to
8be2c78
Compare
I think this looks reasonable from a convenience point of view, but it's kinda defeating one of the major reasons |
@garyb I could write these using the FFI if you prefer. The reason I need these is because there's web ui related APIs that work heavily with records consisting almost entirely of |
I'm not sure resorting to the FFI will help, but lemme try something out a minute, I have an idea that might work. |
Ok, the good news is: it works! The bad news is: it only works when you do it outside of this module 😭. I'd consider that something that should be fixed in the compiler though. So my idea is just: just use full saturation when defining the instances too. For example: instance semigroupEffectFn2 :: Semigroup r => Semigroup (EffectFn2 a b r) where
append f1 f2 = mkEffectFn2 \x y -> runEffectFn2 f1 x y <> runEffectFn2 f2 x y If you write a function that does this outside of the module you can see that when compiled it'll produce this JS: var foo = function (dictSemigroup) {
return function (f1) {
return function (f2) {
return function (x, y) {
return Data_Semigroup.append(Effect.semigroupEffect(dictSemigroup))(function () {
return f1(x, y);
})(function () {
return f2(x, y);
})();
};
};
};
}; Rather than: var foo = function (dictSemigroup) {
return function (f1) {
return function (f2) {
return Effect_Uncurried.mkEffectFn2(Data_Semigroup.append(Data_Semigroup.semigroupFn(Data_Semigroup.semigroupFn(Effect.semigroupEffect(dictSemigroup))))(Effect_Uncurried.runEffectFn2(f1))(Effect_Uncurried.runEffectFn2(f2)));
};
};
}; |
The thing that breaks my heart is I actually tediously wrote all this stuff expanded out like that a couple days ago, then I was like AHA, I AM SO SMART, and deleted all the explicit parameters. Should I do the same thing for all the monoid instances ( |
😄 in any other situation eta-reduction is completely fine, it's just the Yeah, I think doing the monoid instances similarly makes sense. |
Oof, I didn’t realize this would remove the uncurrying — which is the primary reason I reach for these functions. Thanks for the explanation @garyb |
Ok, I've eta-expanded all of them. |
I think they could use a documentation comment (internal, not for Pursuit), so that future people working on this understand the reason for eta-expansion. |
@thomashoneyman How's that? |
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.
Uncurrying is also good for JS compatibility for when you specifically want to be able to call functions as f(a, b, c), which is more idiomatic in JS, instead of f(a)(b)(c).
Plus, EffectFn removes the thunk so you can just call f(a, b) instead of f(a)(b)().
I’m not totally sure how much of that belongs in a comment here, but just for some extra context. So long as the comment helps ensure future edits don’t attempt to clean things up by removing eta expansion I think it’s good.
@thomashoneyman I think the PR is set to allow commits from maintainers, so if you want to flesh out the comment so it captures this information please feel free. |
I am not a maintainer, unfortunately 😄, but I think omitting |
Speaking of, @garyb I'm not able to merge this. |
These are both covered by the existing doc comments surely? |
I don’t think this is quite right. The comment is talking about the emitted code for the instances themselves, not the objects you end up with when you use these instances. Both variants (eta-expanded or not) will look the same from outside of this module. The only difference between them is that eta-expanding means that we end up with fewer function objects being allocated in the implementation - i.e. it is a matter of efficiency. |
Yes; the module has a lengthy comment explaining this in detail. It doesn't need to be repeated.
In that case I misunderstood. Thanks for clarifying, and the comment seems fine as-is with that in mind. |
Ah, whoops. I wish Github would make it easier for conversation participants to contribute tweaks to a PR directly, it would make the process so much faster. |
I think this is good as-is; I think the only remaining question is whether we want to wait until the optimizer is fixed so that it fires on these instances or not. Personally I think it’s probably fine to merge this now. |
Thanks! |
No description provided.