Repository navigation
Please provide instance for (Enum a, Bounded a) for Random #21
Description
Activity
- changed the title
[-]Please provide instance for (Enum a, Bounded a)[/-][+]Please provide instance for (Enum a, Bounded a) for Random[/+]on Oct 4, 2014 What instance do you have in mind,
instance (Bounded a, Enum a) => Random a where ...? There can't be such an instance, since it would overlap with every other instance.I thought there was a most specific instance rule?
The instance would just pick a random constructor from those available (range known by Bounded), evenly distributed among all the enumerations (defined by Enum). The implementation is not hard, I just haven't written it or opened a PR or anything yet.
Essentially, the best case scenario would be if the compiler could derive Random, but it can't, so having an Enum/Bounded instance is the closest thing to it, since it will derive those automatically for you.
This would prevent any user derived instances. If you manufactured a newtype for just giving this instance, that might be more tenable. But even then, this also implicitly assumes a uniform distribution is always the correct default, and I'm not sure if thats true! (Or that every Bounded instance is a properly lawful one, which I'd hope but wouldnt want to impose.)
The analogous monoids induced by
NumuseSumandProductnewtypes, so i think any analogous choice here would needs be using the same strategy. likeUniformBoundednewtype or some suchI kind of got the impression that the Random typeclass implied uniform, but no?
At least, all the existing instances seem to be uniform, and I can't think of a case where you wouldn't just plug something on top of the linear distr to give the different distribution you need.
A reasonable default instance is:
instance Random Action where randomR (a, b) g = case randomR (fromEnum a, fromEnum b) g of (x, g') -> (toEnum x, g') random g = randomR (minBound, maxBound) g
It's tricky boilerplate that would be easy to get wrong and that you just copy-paste.
Maybe Random could export:
defaultBoundedEnumRandomR :: (Bounded a, Enum a, RandomGen g) => (a, a) -> g -> (a, g) defaultBoundedEnumRandomR (a, b) g = case randomR (fromEnum a, fromEnum b) g of (x, g') -> (toEnum x, g') defaultBoundedEnumRandom :: (Bounded a, Enum a, RandomGen g) => g -> (a, g) defaultBoundedEnumRandom g = defaultBoundedEnumRandomR (minBound, maxBound) g
And then users could simply do:
instance Random Action where randomR = defaultBoundedEnumRandomR random = defaultBoundedEnumRandom
Reacted by Vilem Liepeltexporting some default methods might be good. interesting idea!
defaultBoundedEnumRandomR :: (Bounded a, Enum a, RandomGen g) => (a, a) -> g -> (a, g) defaultBoundedEnumRandom :: (Bounded a, Enum a, RandomGen g) => g -> (a, g)These would also be useful to use directly (rather than in a Random instance): suppose you import a type that is an instance of Bounded and Enum but not Random, and you don't want to define an orphan Random instance. So, we could just leave
defaultout of the name.The first one doesn't require
Boundedeither, so we could drop that from the name too.Reacted by Vilem LiepeltThis would be really nice to have.
Ah yes, another +1 on this .. it’s 3 year’s old, I had forgotten all about it .
Is PR accepted ?
- I’m working on a new release. Stay tuned.…On Mon, Oct 30, 2017 at 8:40 PM k.vanberendonck ***@***.***> wrote: Is PR accepted ? — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#21 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AAAQwmrleSss9xVAF--nbAk2yXlTUfL9ks5sxmx0gaJpZM4CqzBl> .
I'm not convinced that sprinkling a couple of
fromEnum/toEnumis that much of boilerplate. It certainly does not justify introducing overlapping instances.However, I would not particularly oppose a PR, introducing
uniformBoundedEnum :: (Enum a, Bounded a, StatefulGen g m) => g -> m aor something similar.Reacted by Alexey KuleshevichI think we should introduce newtype wrapper which allows to derive Uniform/UniformRange instances using DerivingVia
newtype UniformEnum a = UniformEnum a instance Enum a => UniformRange (UnniformEnum a) where ... instance (Bounded a, Enum a) => Uniform (UnniformEnum a) where ... data RGB = R | G | B deriving (Enum.Bounded) deriving Uniform via UniformEnum RGB
Reacted by chessai and Ashlynn Anderson@Shimuuar that looks good to me!
- linked a pull request that will close this issueAdd uniformEnumM and uniformEnumRM #104
on May 8, 2021 Closing as done in #104. Feel free to reopen if there is a specific motivation to use this feature via old
Randominterface.Reacted by Kyle Van Berendoncknewtype UniformEnum a = UniformEnum a instance Enum a => UniformRange (UniformEnum a) where ... instance (Bounded a, Enum a) => Uniform (UniformEnum a) where ... data RGB = R | G | B deriving (Enum, Bounded) deriving Uniform via UniformEnum RGB
[typos corrected]
Sorry to resurrect an old thread, but I felt I should point out that this just doesn't work:
• Couldn't match representation of type: m (UniformEnum RGB) with that of: m RGB arising from the coercion of the method ‘uniformM’ from type ‘forall g (m :: * -> *). System.Random.Internal.StatefulGen g m => g -> m (UniformEnum RGB)’ to type ‘forall g (m :: * -> *). System.Random.Internal.StatefulGen g m => g -> m RGB’ Note: We cannot know what roles the parameters to ‘m’ have; we must assume that the role is nominal. • When deriving the instance for (Uniform RGB)typecheck(GHC-18872)I'm not all that familiar with roles, so I don't know if there's a simple way around this. I suspect not, since this looks similar at a glance to what @amesgen wrestled with in #96.
@georgefst Here is the reason why it doesn't work: #185 (comment)
Reacted by George Thomas
It would be really nice to be able to do something like this:
The implementation for
(Enum a, Bounded a) =>can cheat a little to get a valid range (psuedo, for randomRIO since it's easier/shorter to show):Note the usage of the underlying instance for
Intto select a constructor.It would have been magical if we could have just a
Enum a =>instance, but I can't think of a way to do it.