1

I have this datatype

newtype Dimension a b = MkDimension b

Whenever it is properly formatted (e.g. satisfies theformat constraint), I want to derive a set of classes. I do not want aDimension which does not satisfy theformat 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 deriveapplicative,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 thatfromIntegral is only allowed on properly formatted dimensions.

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

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

askedSep 8 at 19:11
Ashok Kimmel's user avatar
4
  • Say a bit more about whatDimension represents. It's hard to answer right now. Generally, I would recommend to avoid the temptation to derive All tEh kLaSseS for your custom data types, and in particular notNum. People do that all to often, and it subverts the whole point of having a strong type system that makes it easy to getjust the right results, instead of weird unexpected behaviour.CommentedSep 8 at 19:21
  • You haven't told us anything about what "theformat constraint" means. But in general I doubt thatderiving is going to be sufficient for you; you will almost certainly have to do those derivations manually.CommentedSep 8 at 19:42
  • I added the definition of format and explained what I wanted it to do.CommentedSep 8 at 19:50
  • 1
    Ok, so this type shoulddefinitely not haveNum instance - it would be completely the wrong interface. Instead, you should implementVectorSpace plus a custom multiplication, that takes care so e.g. the product of two lengths is an area (different type).CommentedSep 8 at 20:31

1 Answer1

2

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.

answeredSep 8 at 21:20
Daniel Wagner's user avatar
Sign up to request clarification or add additional context in comments.

3 Comments

What should I use then? Num is a mess, but I want addition and subtraction using the common operators without needing special prelude imports.
As I commented earlier,VectorSpace is the appropriate abstraction for this kind of thing. It's a lightweight dependency, no reason not to use it. If you find thea ^+^ b syntax ugly, you can alwaysimport Prelude hiding ((+), (-)) and locally defineinfixl 6 +; (+)=(^+^).
Are there any common type family-based multiplication functions in use?

Your Answer

Sign up orlog in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to ourterms of service and acknowledge you have read ourprivacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.