Defining an Ordinal type whose enumerated subtypes are not ordinal

Multi tool use


Defining an Ordinal type whose enumerated subtypes are not ordinal
I'm running into issues defining ordinal types whose values may or may not be ordinal.
Basically I have two types, an OrderedType
and an UnorderedType
OrderedType
UnorderedType
data OrderedType = One | Two | Three deriving (Eq, Ord, Show)
data UnorderedType = Red | Blue | Green deriving (Eq, Show)
I have a type whose value constructors take either as an argument:
data WrapperType = WrappedOne OrderedType
| WrappedTwo UnorderedType deriving (Eq, Ord, Show)
Basically, what I want to be able to do is have WrapperType
s be ordered without
having to implement a compare
function for WrappedOne
and WrappedTwo
.
WrapperType
compare
WrappedOne
WrappedTwo
When I try to compile the above I get the following error:
• No instance for (Ord UnorderedType)
arising from the first field of ‘WrappedTwo’ (type ‘UnorderedType’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Ord WrappedType)
Which makes sense, because the stock derived Ord
instance of WrappedType
will try
to compare all values of WrappedTwo
.
Ord
WrappedType
WrappedTwo
In a nutshell, what I want to be able to do is this:
WrappedOne _ < WrappedTwo _ -- True
But without writing an Ord
instance for each type.
Ord
How do I do this?
compare (WrappedTwo Red) (WrappedTwo Green)
i suppose it should be
EQ
– dopatraman
18 mins ago
EQ
I think you should use something other than
Ord
. Although it is not technically a law, I (and many others) think that x == y
should imply f x == f y
for all f
, a law which your proposed instance would surely break. If you keep the derived Eq
instance, your proposal would also violate my expectation that x == y
iff compare x y == EQ
.– Daniel Wagner
17 mins ago
Ord
x == y
f x == f y
f
Eq
x == y
compare x y == EQ
How?
Red == Red
and WrappedTwo Red == WrappedTwo Red
. Same is true for One == One
and WrappedOne One == WrappedOne One
– dopatraman
16 mins ago
Red == Red
WrappedTwo Red == WrappedTwo Red
One == One
WrappedOne One == WrappedOne One
You're right: my original comment was not precise. I've updated it.
– Daniel Wagner
15 mins ago
1 Answer
1
I suggest that you don't do this, for the reasons I discussed in the comments: your Ord
instance and Eq
instance should agree, and your Eq
instance should only equate things that behave the same. Instead, have a view of your data which only has the information you care to compare. So:
Ord
Eq
Eq
data Constructor = Lower | Higher deriving (Eq, Ord, Read, Show)
data Wrapper = WrappedOne Foo | WrappedTwo Bar deriving (Read, Show)
constructor :: Wrapper -> Constructor
constructor (WrappedOne _) = Lower
constructor (WrappedTwo _) = Higher
Now, where you would have called compare wrapperA wrapperB
, instead call compare (constructor wrapperA) (constructor wrapperB)
.
compare wrapperA wrapperB
compare (constructor wrapperA) (constructor wrapperB)
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
What should be the result of
compare (WrappedTwo Red) (WrappedTwo Green)
?– Daniel Wagner
23 mins ago