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.
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.