haskellconstraintsinvariantsderivingderivingvia

Adding constraints to deriving declarations


I have this datatype

newtype Dimension a b = MkDimension b

Whenever it is properly formatted (e.g. satisfies the format constraint), I want to derive a set of classes. I do not want a Dimension which does not satisfy the format constraint to be created.

This also means that if I do this:

newtype Dimension a b = MkDimension b 
    deriving newtype Num

fromIntegral is still capable of producing dimensions which are improperly formatted. What should I do? I want to also derive applicative, monoid, and others which would all give the opportunity to create invalid dimension values.

Details: To ensure that ordering doesn't matter when adding dimensions, I attempted to ensure that a Dimension would never have anything to the 0, and would be fully sorted (e.g. (MkDimension 2 :: Dimension '[ '("Meter",0)] Int) + (MkDimension 4 :: Dimension '[] Int)) would be bad, as they are the same dimension, but we would get a type-error. More realistically, the types could be in the wrong order, also causing an error. (MkDimension 2 :: Dimension '[ '("Meter",1),'("Foot",1)] Int) + (MkDimension 4 :: Dimension '[ '("Foot",1),'("Meter",1)] Int). To stop both of those, I want to make it so that fromIntegral is only allowed on properly formatted dimensions.

type family Has0 a where 
    Has0 '[] = 'False
    Has0 '(_,0) ': _ = 'True
    Has0 _ ': b = Has0 b

type Format a = (a ~ Sort a, Has0 a ~ 'False)

The definition of sort is too long to fit in here.


Solution

  • The answer to the question as asked is to use standalone deriving.

    {-# Language StandaloneDeriving #-}
    deriving instance Format a => Num (Dimension a b)
    

    However, I agree with the comments that this probably isn't wise; especially the type of (*) is probably not sensible in that instance.