Skip to content

HasField instances cannot be defined on newtypes that have a field selector even if that isn't exported

Motivation

I would like to able to provide a HasField instance for reactive-banana Behaviors. Specifically, I want to write

instance HasField x a b => HasField (x :: Symbol) (Behavior a) (Behavior b) where
  getField behavior = behavior <&> getField @x

Unfortunately, GHC refuses to allow me to write this, reporting:

lib/Reactive/Banana/Orphans.hs:36:28: error:
    • Illegal instance declaration for
        ‘HasField x (Behavior a) (Behavior b)’
        Behavior has fields
    • In the instance declaration for
        ‘HasField (x :: Symbol) (Behavior a) (Behavior b)’
   |
36 | instance HasField x a b => HasField (x :: Symbol) (Behavior a) (Behavior b) where
   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

but I disagree that Behavior has fields. Internally Behavior is defined as

newtype Behavior a = B { unB :: Prim.Behavior a }

but that is never exported - no module expect the defining one can see that field.

Proposal

I am able to write the instance.

Edited by Ollie Charles
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information