Я хочу сделать все типы, которые являются экземплярами 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)
Но я знаю, что это плохой стиль, потому что instance (Enum r, Bounded r) => Random r
создает экземпляр для всех r
, только с проверкой типа для Enum
и Bounded
, а не просто введите экземпляр для типов, которые являются Enum
и Bounded
. Это фактически означает, что я определяю экземпляр для всех типов :(
.
Альтернативный том, что я должен написать автономные функции, которые дают мне поведение я хочу и написать какое-нибудь шаблонный для каждого типа я хочу быть экземпляром 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
Есть ли лучшие альтернативы? Как мне решить эту проблему? Должен ли я вообще не пытаться это сделать? Я слишком беспокоюсь о шаблоне?