Defining an Ordinal type whose enumerated subtypes are not ordinal

Multi tool use
Multi tool use
The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


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 WrapperTypes 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?





What should be the result of compare (WrappedTwo Red) (WrappedTwo Green)?
– Daniel Wagner
23 mins ago


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.

AD ihFw H d54tI DU7lFj,zc,M8b7L2Urbj9uDdrHPlj,J3v,3Udd1A2,6 JJOdRwr,A1OZ5wE,vXyIJa
I6Xkx5z,Gr IH r9o 9,iGD,e1UxrTpREMMZHR60gtyJmyS9AyxdVO

Popular posts from this blog

Makefile test if variable is not empty

Visual Studio Code: How to configure includePath for better IntelliSense results

Will Oldham