代码之家  ›  专栏  ›  技术社区  ›  Ollie Saunders

多态类约束实例

  •  6
  • Ollie Saunders  · 技术社区  · 15 年前

    我要使所有类型都是 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 ,只需类型检查 枚举 有界 而不仅仅是将实例放在 枚举 有界 . 这实际上意味着我正在为所有类型定义一个实例 :( .

    另一种方法是,我必须编写独立的函数,为我想要的行为提供支持,并为每种类型编写一些样板文件 随机的 :

    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
    

    有更好的选择吗?我应该如何处理这个问题?难道我不应该尝试这个吗?我是不是过于担心样板?

    1 回复  |  直到 14 年前
        1
  •  8
  •   Community Mohan Dere    8 年前

    是的,正如我刚才对 slightly related question ,您可以使用一个新的类型包装器-这是制作此类实例的常见安全方法,不会干扰整个社区。

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

    通过这种方式,想要使用此实例的用户只需包装(或展开)调用:

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