Proposal: Generalize the RandomGen and Random classes
Simon PeytonJones
simonpj at microsoft.com
Thu Oct 7 04:35:37 EDT 2010
 > RandomGen and Random classes assume generators produce Int values.
 > This is nonideal as many high speed generators produce special values
 > (ex: doubles) or generic values (bit streams / bytestrings) that can
 > be converted directly to types easier than coercing to Int then to an
 > 'a' via the Random class.
On looking at this again, I think the proposed API looks overelaborate. Surely there must be a better way?
The current design (trimmed down) is like this:
class RandomGen g where
next :: g > (Int, g)
class Random a where
randoms :: forall g. RandomGen g => g > [a]
The logic is
* RandomGen is a way to get a supply of bits, here expressed as Int
Maybe the class should have been called (BitSupply g)
* Random is a way to turn a supply of bits into values of some arbitrary type a
Notice that a single instance of Random, say Random Integer, will work for
*arbitrary* generators g.
In the proposal each instance of RandomGen produces values of a single type 'v', functionally dependent on the generator type 'g':
class RandomGen g v  g > v where
next :: g > (v, g)
Then there's a conversion from the fixedbutunknown type 'v' to an arbitrary type 'a':
class Random a v where
randoms :: forall g. RandomGen g v => g > [a]
The original message proposing the change omitted the 'v' parameter from Random. Yes, it's complicated: the intermediate type 'v' is really just a bitsupply.
Now we need to make a new instance of Random for each bitsupply type 'v'. It's not *so* bad: we expect to have
* Lots of generators g
* Lots of result types a
* Rather few bitsupply types v; perhaps just Int and Bytestring?
We need a Random instance for each (a,v) pair.
The types are a bit subtle. Look at the type of
randoms :: (Random a v, RandomGen g v) => g > [a]
A call site presumably fixes, g and a; then the functional dependency fixes v; then we can find instances for (Random a v, RandomGen g v).
In typefunction form it would have to look like this:
class RandomGen g where
type GenVal g :: *
next :: g > (GenVal g, g)
class Random a v where
randoms :: forall g. (RandomGen g, v ~ GenVal g) => g > [a]
which makes the functional dependency explicit.
It's not a silly design. But it's a rather abstract one, and there's always a danger of going overboard with abstraction in Haskell :).
How many bitsupply types v do you want? Would it be enough to ask generators to generate all of them? Antoine suggested this:
class RandomGen g where
nextInt :: g > (Int, g)
nextByteString :: g > (ByteString, g)
But unlike Antoine's suggestion, I think we only need a tiny handful of bit supply types, because the Random class does the impedence matching to other types.
Simon
 Original Message
 From: librariesbounces at haskell.org [mailto:librariesbounces at haskell.org] On
 Behalf Of Thomas DuBuisson
 Sent: 06 October 2010 23:53
 To: Haskell Libraries; Milan Straka; Yitz
 Subject: Re: Proposal: Generalize the RandomGen and Random classes

 All,
 There has been precious few comments on this proposal (ending in 2
 days). Conversation has thus far been:

 Accept (1  me)
 No  Random is H98 and changing it is not acceptable (2  Milan, Yitz)
 Unknown Stance (2  SPJ, Antonie Latter)

 Mostly I'm hoping for more comments. If you found the splittable
 debate of value then I'd imagine this aspect of Random would concern
 you too.


 In response to the idea that we can't or shouldn't change H98:

 Yitz:
 > If those extensions
 > are all added to Haskell 2011 or whatever, then it could be considered.

 AFAIK, all accepted parts of Haskell standards are implemented FIRST
 (typically as a GHC extension or package) then considered for
 Haskell'. The Haskell2010 and Haskell98 packages, which you can
 import, can contain their own definition of System.Random  this could
 be static without stagnating all libraries that are mentioned in a
 Haskell standard.

 Milan:
 > I personally do not think it is worth to modify the Random module, which
 > dates back to at least Haskell 98. Maybe a new package on the Hackage?

 So because it is old we can't modify it? The point of changing the
 library is to benefit a broader portion of the community. We could
 stop any and all changes to package X and make a new package every
 time but this isn't a sufficient argument to me.

 If peoples only objections are compatibility then we can queue this
 change up with the next API breaking change, unless there will never
 again be such a change.

 Cheers,
 Thomas


 On Tue, Sep 14, 2010 at 5:11 PM, Thomas DuBuisson
 <thomas.dubuisson at gmail.com> wrote:
 > Hello,
 > RandomGen and Random classes assume generators produce Int values.
 > This is nonideal as many high speed generators produce special values
 > (ex: doubles) or generic values (bit streams / bytestrings) that can
 > be converted directly to types easier than coercing to Int then to an
 > 'a' via the Random class.
 >
 > See 4315 [1] for the patch.
 >
 > Period of discussion: Till October 8 (3.5 weeks, giving a little time
 > after ICFP for last minute debate)
 >
 > Specifically, this proposal:
 >
 > 1) Alters RandomGen:
 >
 > from:
 > class RandomGen g where
 > next :: g > (Int, g)
 > genRange :: g > (Int, Int)
 >
 > to
 >
 > class RandomGen g v  g > v where
 > next :: g > (v, g)
 > genRange :: g> (v,v)
 >
 > 2) Alters Random:
 >
 > From:
 >
 > class Random a where
 > randomR :: RandomGen g => (a,a) > g > (a,g)
 > random :: RandomGen g => g > (a, g)
 > randomRs :: RandomGen g => (a,a) > g > [a]
 > randoms :: RandomGen g => g > [a]
 > randomRIO :: (a,a) > IO a
 > randomIO :: IO a
 >
 > to
 >
 > class Random a where
 > randomR :: RandomGen g v => (a,a) > g > (a,g)
 > random :: RandomGen g v => g > (a, g)
 > randomRs :: RandomGen g v => (a,a) > g > [a]
 > randoms :: RandomGen g v => g > [a]
 >
 >
 > Additional Points of Debate
 > 1) Because random[R]IO can not be part of the new Random instance with
 > a sensible default, these have been moved to toplevel functions:
 >
 > randomRIO :: (Random a Int) => (a,a) > IO a
 > randomIO :: (Random a Int) => IO a
 >
 > Other options exist and I'm open to them. I'm just being upfront
 > about what the patch currently does.
 >
 > 2) All preexisting instances of "Random x" for some concrete 'x' have
 > been modified to be "instance Random x Int". As 'Int' was the
 > previous (hardcoded) default for RandomGen this is simply matching the
 > behavior. More instances are possible and probably make sense now.
 > Alternatively, one could argue for zero default instance as they can
 > collide with how a particular user wishes types to be coerced.
 >
 > 3) Notsonew extensions are used to enable these changes. Extensions
 > include MultiParamTypeClasses, FlexibleContexts, and FunDeps.
 >
 > 4) A patch is included bumping the version from 1.0.0.x to 1.1.0.0.
 >
 > Cheers,
 > Thomas
 >
 > [1] http://hackage.haskell.org/trac/ghc/ticket/4315
 >
 _______________________________________________
 Libraries mailing list
 Libraries at haskell.org
 http://www.haskell.org/mailman/listinfo/libraries
More information about the Libraries
mailing list