Question

Note: I may not need to add Scalar to Eq, although it should solve the problem if I could figure out how to do just that.

So I'm trying to add some functionality to the ForceLayout module. Adding mass to Particles like so:

data Particle v = Particle { 
                         _pos   :: Point v
                       , _vel   :: v
                       , _force :: v
                       , _mass :: Scalar v
                       }
    deriving (Eq, Show)

But Scalar is not in Eq or Show! So this wont compile. Mass should be a scalar "compatible" with the other vectors though. How can I reconcile this? I don't understand type families sufficiently to analyse this situation. I've tried but they are mighty hard to grasp. Not sure if adding Scalar to Eq is necessary or possible.

Was it helpful?

Solution

If you want to show the mass field, the show instance is going to have to look like

instance (Show v, Show (Point v), Show (Scalar v)) => Show (Particle v) where

Arguably, the fact that GHC doesn't work this out is a bug, or at least a missing feature. Luckily, with some extension heavy lifting, we can give it the context ourselves:

{-# LANGUAGE StandaloneDeriving, TypeFamilies,
    FlexibleContexts, UndecidableInstances #-}
{- ... -}

deriving instance (Show v, Show (Point v), Show (Scalar v)) => Show (Particle v)

This is a "standalone deriving declaration" as described in the GHC user guide, and its purpose here is basically so that we can specify a context that GHC wouldn't normally be able to work out.

That ought to do the trick. I'm a little worried about the UndecidableInstances, since it does seem like it ought to be possible to define instances of Point and Scalar such that this instance is circular, but despite my best efforts I haven't been able to make the typechecker loop, so it's probably fine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top