Oll*_*ers 6 haskell types typeclass instances
我要让那些实例的所有类型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)
Run Code Online (Sandbox Code Playgroud)
但我知道这是不好的风格,因为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
Run Code Online (Sandbox Code Playgroud)
还有更好的选择吗?我该如何处理这个问题?我根本不应该尝试这个吗?我过于担心样板吗?
是的,正如我刚刚回答了一个稍微相关的问题,您可以使用newtype包装器 - 这是制作此类实例而不会烦扰整个社区的常用且安全的方法.
newtype RandomForBoundedEnum a = RfBE { unRfBE :: a}
instance (Enum a, Bounded a) => Random (RandomForBoundedEnum a) where
....
Run Code Online (Sandbox Code Playgroud)
通过这种方式,想要使用此实例的用户只需要打包(或解包)调用:
first unRfBE . random $ g :: (Side, StdGen)
Run Code Online (Sandbox Code Playgroud)