Wizek
Wizek

Reputation: 4993

Could not deduce (Reflex t0) arising from a use of ‘never’

Anyone knows how I could deal with errors like `Could not deduce (Reflex t0) arising from a use of ‘never’?

I am refactoring a portion of an app, which means a few never events don't get used, but since they are never to begin with, I don't care.

Can I make GHC not care somehow as well?

I know about -XExtendedDefaultRules which likely at least helps to specialize the type from forall t a. Event t a to forall t. Event t ()

And I want to specialize t as well to whatever value GHC would accept, since it results in dead code anyway.

Is there something I can write in the default (...) statement that could work? Or is that similarly impossible to writing default (IO) to specialize non-fully-specified monads to IO?

Edit: On #reflex-frp @dalaing asked for a code example, and this is what I put together for him: https://gist.github.com/Wizek/d14aada2d75637cb4f424f8a324c7ad7

Section 1 and 2 compile, 3 doesn't. But I want to make 3 compile as well since the compiler is complaining about ambiguity in something that can only be dead code.

Upvotes: 2

Views: 133

Answers (2)

trevor cook
trevor cook

Reputation: 1590

Using

foo :: forall t m. MonadWidget t m => m ()
foo = do
  let buttonEv = never @t
  buttonEv <- button "click me"
  clicksCountDy <- count buttonEv
  display clicksCountDy

It's really not a problem with never here. Its a problem of not binding the action to the current monad. The line in question could have been anything:

let buttonEv = button "never click me"

This would create a button widget action, but never "connect" it to the current widget. You wouldn't see the "never click me" button in your app.

On the other hand, if you connected the never event to your widget,

buttonEv <- return never

you would no longer need the @t annotation.

Ultimately though, I find that the -- annotation works well in instances of dead code.

-- let buttonEv = never

Keep the code around if you must, but this is the best way to tell the compiler that the code is unimportant.

Upvotes: 0

Wizek
Wizek

Reputation: 4993

Together with @dalaing on #reflex-frp we found that never :: Event t () works if -XScopedTypeVariables is enabled and the parent widget has a forall t. Reflex t => constraint or similar.

For example, section 3 in the linked code example could be modified as such:

{-# language ScopedTypeVariables #-}

main = run 3000 $ mainWidget foo

foo :: forall t m. MonadWidget t m => m ()
foo = do
  let buttonEv = never :: Event t ()
  buttonEv <- button "click me"
  clicksCountDy <- count buttonEv
  display clicksCountDy

Which compiles. But it is inconvenient to have to specify the event type everywhere, and it may also not be as DRY as we want, so -XPartialTypeSignatures could help via never :: Event t _

Or even better, I find, we can do never @t with -XTypeApplications:

{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}

main = run 3000 $ mainWidget foo

foo :: forall t m. MonadWidget t m => m ()
foo = do
  let buttonEv = never @t
  buttonEv <- button "click me"
  clicksCountDy <- count buttonEv
  display clicksCountDy

So from this point onwards, I might just make it a policy that in my reflex related code portions I never write never, and always write (never @t), which solves this problem perfectly for the most part.

I just still wish GHC could be asked to be more lenient in type checking dead code in general, not just when it comes to reflex, but perhaps that is impossible for now.

Upvotes: 3

Related Questions