多态类约束实例
我想让所有属于 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
创建一个实例,只需对 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
有更好的选择吗?我应该如何解决这个问题?我是否应该过度担心样板?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,正如我刚刚回答的稍微相关的问题,您可以使用新类型包装器 - 这是创建此类实例而不打扰整个社区的常见且安全的方法。
通过这种方式,想要使用此实例的用户只需包装(或解开)调用:
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.
In this manner, users who want to use this instance simply need to wrap (or unwrap) the calls: