我想使所有属于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)=>;随机r
为所有r
枚举和有界
进行类型检查,而不是仅将实例放在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
还有更好的选择吗?我应该如何处理这个问题?难道我根本就不应该这样做吗?我是不是太担心样板了?