Limited Class Polymorphic Instances

I want all types that are instances of Enumand Boundedare also instances Random. The following code does this and should work (with the appropriate extensions):

import System.Random

instance (Enum r, Bounded r) => Random r where
   randomR (hi, lo) = inFst toEnum . randomR (fromEnum hi, fromEnum lo)
      where inFst f (x,y) = (f x, y)
   random = randomR (maxBound, minBound)

But I know that this is a bad style because it instance (Enum r, Bounded r) => Random rcreates an instance for everyone r, only with type checks for Enumand Boundedinstead of just putting the instance in types Enumand Bounded. This actually means that I am defining an instance for all types :(.

An alternative is that I have to write autonomous functions that give me the behavior I want and write some patterns for each type. I want to be an instance Random:

randomBoundedEnum :: (Enum r, Bounded r, RandomGen g) => g -> (r, g)
randomBoundedEnum = randomRBoundedEnum (minBound, maxBound)

randomBoundedEnumR :: (Enum r, Bounded r, RandomGen g) => (r, r) -> g -> (r, g)
randomBoundedEnumR (hi, lo) = inFst toEnum . randomR (fromEnum hi, fromEnum lo)
   where inFst f (x,y) = (f x, y)

data Side = Top | Right | Bottom | Left 
   deriving (Enum, Bounded)

-- Boilerplatey :( 
instance Random Side where
   randomR = randomBoundedEnumR
   random = randomBoundedEnum

data Hygiene = Spotless | Normal | Scruffy | Grubby | Flithy
   deriving (Enum, Bounded)

-- Boilerplatey, duplication :(
instance Random Hyigene where
   randomR = randomBoundedEnumR
   random = randomBoundedEnum

? ? ? ?

+5
1

, , newtype - , .

newtype RandomForBoundedEnum a = RfBE { unRfBE :: a}
instance (Enum a, Bounded a) => Random (RandomForBoundedEnum a) where
    ....

, , , ( ) :

first unRfBE . random $ g :: (Side, StdGen)
+8

All Articles