多态类约束实例

发布于 2024-09-27 20:00:41 字数 1497 浏览 8 评论 0原文

我想让所有属于 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

有更好的选择吗?我应该如何解决这个问题?我是否应该过度担心样板?

I want to make all types that are instances of Enum and Bounded also an instances of Random. The following code does this and should work (with the appropriate extensions enabled):

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)

But I am aware this is bad style because instance (Enum r, Bounded r) => Random r creates an instance for all r, just with type checks for Enum and Bounded rather than just putting an instance on types that are Enum and Bounded. This effectively means I'm defining an instance for all types :(.

The alternate is that I have to write standalone functions that give me the behavior I want and write some boilerplate for each type I want to be an instance of 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

Are there any better alternatives? How should I manage this problem? Should I not even be attempt this at all? Am I overly worried about boilerplate?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

春夜浅 2024-10-04 20:00:41

是的,正如我刚刚回答的稍微相关的问题,您可以使用新类型包装器 - 这是创建此类实例而不打扰整个社区的常见且安全的方法。

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

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

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

Yes, as I just answered to a slightly related question, you can use a newtype wrapper - this is the common and safe way to make such instances without annoying the entire community.

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

In this manner, users who want to use this instance simply need to wrap (or unwrap) the calls:

first unRfBE . random $ g :: (Side, StdGen)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文