Полиморфные экземпляры с ограничениями класса

Я хочу создать все типы, которые являются экземплярами Enum и Bounded также экземпляры Random . Следующий код делает это и должен работать (с соответствующими расширениями):

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)

Но я знаю, что это плохой стиль, потому что экземпляр (Enum r, Bounded r) => Random r создает экземпляр для all r , только с проверками типов для Enum и Bounded , а не просто помещать экземпляр в типы, которые являются Enum и Ограниченный . Фактически это означает, что я определяю экземпляр для всех типов : (.

Альтернативой является то, что я должен писать автономные функции, которые дают мне поведение, которое я хочу, и написать некоторый шаблон для каждого типа, который я хочу быть экземпляром 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

Есть ли какие-нибудь лучшие альтернативы? Как мне решить эту проблему? Не стоит ли мне вообще пытаться это сделать? Я слишком беспокоюсь по поводу шаблонов?

6
задан Don Stewart 23 April 2011 в 22:45
поделиться