Reputation: 971
I define my own datatype.
data Row = A | B | C deriving (Show,Eq,Ord)
The question is, if there is a more elegant way to define my range than this?
instance Ix Row where
range (A,A) = [A]
range (A,B) = [A,B]
range (A,C) = [A,B,C]
range (B,B) = [B]
range (B,C) = [B,C]
range (C,C) = [C]
range _ = []
Upvotes: 5
Views: 1071
Reputation: 477533
Enum
instanceYes, you can make Row
an instance of Enum
, in fact you do not have to define it yourself:
data Row = A | B | C deriving (Show, Eq, Ord, Enum)
This means that we can now use "range notation". For example:
Prelude> [A .. C]
[A,B,C]
Prelude> [A .. B]
[A,B]
Prelude> [C .. B]
[]
So we can now define our Ix
instance as:
instance Ix Row where
range (x, z) = [x .. z]
index (x, _) y = fromEnum y - fromEnum x
inRange (x, z) y = x <= y && y <= z
Or even without parameters:
instance Ix Row where
range = uncurry enumFromTo
-- ...
In case you do not want to make it an Enum
instance (I do not see any reason here not to, but this is of course a rather hypothetical datatype). We can construct a list by using recursion and each time calculating the successor:
instance Ix Row where
range (x, z) = go x
where go y | y > z = []
go A = A : go B
go B = B : go C
go C = [C]
Although the code fragment above is still a large amount of work, it scales linear with the number of data constructors, whereas an exhaustive approach, would scale quadratic with the number of data constructors (not in time complexity, but in the amount of code).
Upvotes: 11