Skip to content
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

Merged
merged 1 commit into from
Mar 31, 2020

Conversation

endgame
Copy link
Contributor

@endgame endgame commented Mar 5, 2020

@mpickering asked me whether it was possible to use Reflex.Profiled
with reflex-basic-host. I said that it probably wouldn't be too
hard, 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. I
don't really understand Reflex.Profiled (I just hit things with
coerce and lift until GHC was happy), so please look closely to
make sure useful things aren't getting dropped on the floor.

@endgame endgame changed the title @mpickering asked me whether it was possible to use Reflex.Profiled Lifting instances for Reflex.Profiled Mar 5, 2020
@ryantrinkle
Copy link
Member

@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:
haskell/haskell-ide-engine#1580
haskell/cabal#6483
haskell/cabal#6211

@endgame
Copy link
Contributor Author

endgame commented Mar 5, 2020

Many currently-open PRs have travis failures on 8.6.5 in similar-looking ways. Will this block merging?

@endgame
Copy link
Contributor Author

endgame commented Mar 12, 2020

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?

@3noch
Copy link
Member

3noch commented Mar 12, 2020

@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.

@endgame
Copy link
Contributor Author

endgame commented Mar 12, 2020

@3noch To be clear, are you asking for one commit per instance? I can do that.

@3noch
Copy link
Member

3noch commented Mar 12, 2020

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!

@endgame endgame force-pushed the profiled-do-you-even-lift branch from b4ee1f2 to f7f20db Compare March 16, 2020 09:15
@endgame
Copy link
Contributor Author

endgame commented Mar 16, 2020

Split the minor fixes off into #399, #400, #401 .

@endgame
Copy link
Contributor Author

endgame commented Mar 16, 2020

This PR still uses the new name for BehaviorWriter, introduced in #401 . The 3 other PRs should be uncontroversial. Once they're in or rejected, I will rebase this on latest develop and we can talk about which instances are OK to have.

@3noch
Copy link
Member

3noch commented Mar 16, 2020

Thank you!

@3noch
Copy link
Member

3noch commented Mar 30, 2020

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)
Copy link
Member

@matthewbauer matthewbauer Mar 30, 2020

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:

Suggested change
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f)
newEventWithLazyTriggerWithOnComplete f = coerce <$> lift ((newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> m (Event t a)) f)

Copy link
Member

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)

Copy link
Contributor Author

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
Copy link
Member

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

Copy link
Contributor Author

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) ())

@matthewbauer
Copy link
Member

matthewbauer commented Mar 30, 2020

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 t is used instead of ProfiledTimeline t can be used to make sure these are correct.

Copy link
Contributor Author

@endgame endgame left a 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)
Copy link
Contributor Author

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
Copy link
Contributor Author

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) ())

@endgame endgame force-pushed the profiled-do-you-even-lift branch from f7f20db to 55abd6b Compare March 30, 2020 22:06
@endgame
Copy link
Contributor Author

endgame commented Mar 30, 2020

Note that this branch is still based off #400 where MonadQuery has a Monad superclass. Once #400 is merged, I'll rebase this so it can merge cleanly.

@endgame endgame force-pushed the profiled-do-you-even-lift branch from 55abd6b to 217b136 Compare March 30, 2020 22:48
@endgame
Copy link
Contributor Author

endgame commented Mar 30, 2020

Rebased on develop and force-pushed to tidy up.

Copy link
Collaborator

@cgibbard cgibbard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@3noch 3noch merged commit 2f5f87a into reflex-frp:develop Mar 31, 2020
@endgame endgame deleted the profiled-do-you-even-lift branch March 31, 2020 00:56
@matthewbauer
Copy link
Member

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.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants