When I try this:
import GHC.Generics (Generic)
import Control.DeepSeq (NFData(..))
import Data.Vector.Generic (Vector)
data Entry a = Entry !Bool a
deriving (Generic, NFData)
-- The variable @v@ is meant to be instantiated with a 'Vector'
-- type. Most operations for the type have a @Vector v (Entry a)@
-- constraint.
newtype DenseIntMap v a = DenseIntMap (v (Entry a))
instance NFData (v (Entry a)) => NFData (DenseIntMap v a) where
rnf (DenseIntMap va) = rnf va
...I get this error:
/Users/casillas/GitHub/tau-sigma/src/TauSigma/Util/DenseIntMap.hs:53:10:
Constraint is no smaller than the instance head
in the constraint: Vector v (Entry a)
(Use UndecidableInstances to permit this)
In the instance declaration for ‘NFData (DenseIntMap v a)’
/Users/casillas/GitHub/tau-sigma/src/TauSigma/Util/DenseIntMap.hs:53:10:
Constraint is no smaller than the instance head
in the constraint: NFData (v (Entry a))
(Use UndecidableInstances to permit this)
In the instance declaration for ‘NFData (DenseIntMap v a)’
Using UndecidableInstances
indeed makes it go away, but I'm wary of using that extension. Is there some other way to make things work in this case? (Without changing the types too much, preferably.)
Warning: I haven't tested any of this code.
The approach that seems cleanest to me is to follow a Prelude.Extras
-style path:
class NFData1 f where
rnf1 :: NFData a => f a -> ()
You can now write, for each vector type, something like
instance NFData1 V where
rnf1 = rnf
And then
instance (NFData1 v, NFData a) => NFData (DenseIntMap v a) where ...
An alternative approach that may fit your current code better is to think about v
as a Vector
explicitly. Instead of worrying about how v a
would prefer to force itself, ram your own notion down its throat by folding: something like
instance (Vector v a, NFData a) => NFData (DenseIntMap v a) where
rnf = V.foldl' (\() e -> rnf e) ()
This second approach seems likely to play poorly with vector fusion unless you're careful about which vectors you want to force from left to right and which from right to left.