-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Lifting instances for Reflex.Profiled
#398
Conversation
Reflex.Profiled
Reflex.Profiled
@endgame Awesome! It looks like we've gotten the Obsidian CI to work, but Travis is failing on ghc 8.6.5. I don't see how this could be due to your patch, but it would be nice to figure out how to fix this. Here are some things that might be relevant: |
Many currently-open PRs have travis failures on 8.6.5 in similar-looking ways. Will this block merging? |
I'm likely to be tied up for a while and not able to go digging through a CI that I don't understand. Has there been movement elsewhere to un-break this, and if not, will it block merging? |
@endgame You're right. Many other PRs are suffering from the same CI failure. You shouldn't need to solve that. However, can you split this PR into separate PRs for each logical change you made? Each has its own merits but needs to be considered separately from the others. |
@3noch To be clear, are you asking for one commit per instance? I can do that. |
It looks like your commits each represent a valuable contribution on their own, so a PR for each one would be ideal. Some of them should be merged immediately and some may require more thought. I don't want any of your contribution getting stuck! |
b4ee1f2
to
f7f20db
Compare
This PR still uses the new name for |
Thank you! |
This is a legitimate CI failure. |
instance TriggerEvent t m => TriggerEvent (ProfiledTimeline t) (ProfiledM m) where | ||
newTriggerEvent = first coerce <$> lift newTriggerEvent | ||
newTriggerEventWithOnComplete = first coerce <$> lift newTriggerEventWithOnComplete | ||
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f) |
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.
This one looks wrong. Could you add a signature to ensure it's correct with:
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f) | |
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift ((newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> m (Event t a)) f) |
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.
(wrong because you should have to coerce f in some way)
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.
I understand your concern for other instances, but I don't see how it applies here. Why should f
be coerced?
newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> m (Event t a)
-- vs.
newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> ProfiledM m (Event (ProfiledTimeline t) a)
I don't see how f
changes.
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f) | ||
|
||
instance PostBuild t m => PostBuild (ProfiledTimeline t) (ProfiledM m) where | ||
getPostBuild = coerce <$> lift getPostBuild |
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.
This one might be too
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.
Similarly:
getPostBuild :: m (Event t ())
-- vs.
getPostBuild :: ProfiledM m (Event (ProfiledTimeline t) ())
We had an issue with bad instances for Reflex.Profiled before (#389). It's actually pretty easy to accidentally recursively call the "ProfiledTimeline" instance in its own instance definition, instead of the inner timeline. Most of these look pretty reasonable, but newEventWithLazyTriggerWithOnComplete, getPostBuild, and askQueryResult look suspicious. The rule I have is that there should be a coerce happening before the inner instance is called. Adding type signatures to each call in the instance definition so 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.
I've taken your concerns seriously but believe there's nothing to do here. I checked each changed function in this PR by giving the lifted function a partial type signature (e.g., askQueryResult = coerce <$> lift (askQueryResult :: _)
) and checking that GHC does not show ProfiledM
or ProfiledTimeline
in the inferred type.
askQueryResult
and getPostBuild
do not accept arguments, so the is nothing to coerce before passing to the lifted instance, and the function argument to newEventWithLazyTriggerWithOnComplete
does not speak of m
or t
at all.
instance TriggerEvent t m => TriggerEvent (ProfiledTimeline t) (ProfiledM m) where | ||
newTriggerEvent = first coerce <$> lift newTriggerEvent | ||
newTriggerEventWithOnComplete = first coerce <$> lift newTriggerEventWithOnComplete | ||
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f) |
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.
I understand your concern for other instances, but I don't see how it applies here. Why should f
be coerced?
newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> m (Event t a)
-- vs.
newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> ProfiledM m (Event (ProfiledTimeline t) a)
I don't see how f
changes.
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f) | ||
|
||
instance PostBuild t m => PostBuild (ProfiledTimeline t) (ProfiledM m) where | ||
getPostBuild = coerce <$> lift getPostBuild |
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.
Similarly:
getPostBuild :: m (Event t ())
-- vs.
getPostBuild :: ProfiledM m (Event (ProfiledTimeline t) ())
f7f20db
to
55abd6b
Compare
55abd6b
to
217b136
Compare
Rebased on develop and force-pushed to tidy up. |
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.
lgtm
Looks good! Sorry @endgame I wasn't paying close enough attention to how those were setup, but can now confirm with GHCI as well that they are correct. |
@mpickering asked me whether it was possible to use
Reflex.Profiled
with
reflex-basic-host
. I said that it probably wouldn't be toohard, you'd just need lifts here and there.
This PR adds lifting instances for all the classes I could find in
reflex
, and tidies up a couple of warts I found along the way. Idon't really understand
Reflex.Profiled
(I just hit things withcoerce
andlift
until GHC was happy), so please look closely tomake sure useful things aren't getting dropped on the floor.