【问题标题】:Polymorphic class-constrained instances多态类约束实例
【发布时间】:2010-10-15 18:41:05
【问题描述】:

我想让所有作为EnumBounded 实例的类型也成为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 创建了一个实例,只是对EnumBounded 进行类型检查,而不是仅仅在EnumBounded。这实际上意味着我正在为所有类型 :( 定义一个实例。

另一种方法是我必须编写独立的函数来提供我想要的行为,并为我想成为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

还有更好的选择吗?我应该如何处理这个问题?我什至不应该尝试这个吗?我是否过度担心样板文件?

【问题讨论】:

    标签: haskell types typeclass instances


    【解决方案1】:

    是的,正如我刚刚回复 slightly related question 一样,您可以使用新类型包装器 - 这是制作此类实例而又不会惹恼整个社区的常见且安全的方法。

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

    以这种方式,想要使用此实例的用户只需要包装(或解包)调用:

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

    【讨论】:

      猜你喜欢
      • 2015-09-06
      • 1970-01-01
      • 2012-09-06
      • 2014-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      相关资源
      最近更新 更多