System.Random instances for tuples

Ever find yourself wanting to generate a tuple of random things? Instances are trivial to write in Haskell 98: instance (Random a, Random b) => Random (a, b) where randomR ((loL, loR), (hiL, hiR)) g = ((l, r), g'') where (l, g') = randomR (loL, hiL) g (r, g'') = randomR (loR, hiR) g' random g = ((l, r), g'') where (l, g') = random g (r, g'') = random g' Can we add instances like this to System.Random in the random package? -- Dan Burton

On Mon, Apr 16, 2012 at 9:04 PM, Dan Burton
Ever find yourself wanting to generate a tuple of random things? Instances are trivial to write in Haskell 98:
CC'ing the maintainer of the package as well. It looks like it makes sense to me.
instance (Random a, Random b) => Random (a, b) where randomR ((loL, loR), (hiL, hiR)) g = ((l, r), g'') where (l, g') = randomR (loL, hiL) g (r, g'') = randomR (loR, hiR) g' random g = ((l, r), g'') where (l, g') = random g (r, g'') = random g'
Can we add instances like this to System.Random in the random package?
-- Dan Burton
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Dan Burton wrote:
Ever find yourself wanting to generate a tuple of random things? Instances are trivial to write in Haskell 98... Can we add instances like this to System.Random in the random package?
I'm guessing that this was left out because of its surprising side-effect of adding strictness to the first component: If you try to get the value of the second component, the first one is forced. For example, imagine that in randomR the computation for the lower bound on the first component is expensive or bottom, and you only ask for the second component in the calling code. You would really want to use split for this. But not much is known about how to write good random generators with provably good splitting properties. -Yitz

I find the tuple instances for Random useful. On Tue, 17 Apr 2012, Yitzchak Gale wrote:
I'm guessing that this was left out because of its surprising side-effect of adding strictness to the first component: If you try to get the value of the second component, the first one is forced.
I'm not surprised. Without this instance I would wrap 'randomR' in a State monad and then do a liftA2 (,) (State random) (State random) which yields the same behavior. I am thinking about whether your argument reveals a problem for lists. If you do unzip (randoms g) then evaluating one of the result lists will also evaluate parts of the other list. However, this is true for many applications of unzip. For me @randoms :: g -> [(a,a)]@ looks nicer than @case split g of (g0,g1) -> zip (randoms g0) (randoms g1)@.
For example, imagine that in randomR the computation for the lower bound on the first component is expensive or bottom, and you only ask for the second component in the calling code.
Isn't this the same problem as in Ix tuple instances? Are you sure that the bounds for the first component are computed if the second component is evaluated? I think only the 'g' is forced. What about QuickCheck.Arbitrary instance? As far as I remember the current version of QuickCheck has tuple instances.

Alright, as a library proposal we need a discussion period and a deadline for decision. As the maintainer, I personally have no objection but am completely agnostic on the choice between the design alternatives: - Use split, don't add strictness to other tuple components - Don't use split, inject additional strictness. Honestly, since random instances will never include any "interesting" computation I'm not sure why one would ever mind the extra strictness. Perhaps the documentation for the instances should say that bringing the tuple itself to WHNF may evaluate any subset of the tuple components... -Ryan On Thu, Apr 19, 2012 at 10:18 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
I find the tuple instances for Random useful.
On Tue, 17 Apr 2012, Yitzchak Gale wrote:
I'm guessing that this was left out because of its
surprising side-effect of adding strictness to the first component: If you try to get the value of the second component, the first one is forced.
I'm not surprised. Without this instance I would wrap 'randomR' in a State monad and then do a liftA2 (,) (State random) (State random) which yields the same behavior.
I am thinking about whether your argument reveals a problem for lists. If you do unzip (randoms g) then evaluating one of the result lists will also evaluate parts of the other list. However, this is true for many applications of unzip.
For me @randoms :: g -> [(a,a)]@ looks nicer than @case split g of (g0,g1) -> zip (randoms g0) (randoms g1)@.
For example, imagine that in randomR the
computation for the lower bound on the first component is expensive or bottom, and you only ask for the second component in the calling code.
Isn't this the same problem as in Ix tuple instances?
Are you sure that the bounds for the first component are computed if the second component is evaluated? I think only the 'g' is forced.
What about QuickCheck.Arbitrary instance? As far as I remember the current version of QuickCheck has tuple instances.
______________________________**_________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/**mailman/listinfo/librarieshttp://www.haskell.org/mailman/listinfo/libraries

But it's worth mentioning that we have an accepted but not yet released
library proposal to factor "split" out into its own type class.
On Thu, Apr 19, 2012 at 10:31 AM, Ryan Newton
Alright, as a library proposal we need a discussion period and a deadline for decision.
As the maintainer, I personally have no objection but am completely agnostic on the choice between the design alternatives:
- Use split, don't add strictness to other tuple components - Don't use split, inject additional strictness.
Honestly, since random instances will never include any "interesting" computation I'm not sure why one would ever mind the extra strictness.
Perhaps the documentation for the instances should say that bringing the tuple itself to WHNF may evaluate any subset of the tuple components...
-Ryan
On Thu, Apr 19, 2012 at 10:18 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
I find the tuple instances for Random useful.
On Tue, 17 Apr 2012, Yitzchak Gale wrote:
I'm guessing that this was left out because of its
surprising side-effect of adding strictness to the first component: If you try to get the value of the second component, the first one is forced.
I'm not surprised. Without this instance I would wrap 'randomR' in a State monad and then do a liftA2 (,) (State random) (State random) which yields the same behavior.
I am thinking about whether your argument reveals a problem for lists. If you do unzip (randoms g) then evaluating one of the result lists will also evaluate parts of the other list. However, this is true for many applications of unzip.
For me @randoms :: g -> [(a,a)]@ looks nicer than @case split g of (g0,g1) -> zip (randoms g0) (randoms g1)@.
For example, imagine that in randomR the
computation for the lower bound on the first component is expensive or bottom, and you only ask for the second component in the calling code.
Isn't this the same problem as in Ix tuple instances?
Are you sure that the bounds for the first component are computed if the second component is evaluated? I think only the 'g' is forced.
What about QuickCheck.Arbitrary instance? As far as I remember the current version of QuickCheck has tuple instances.
______________________________**_________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/**mailman/listinfo/librarieshttp://www.haskell.org/mailman/listinfo/libraries
participants (5)
-
Antoine Latter
-
Dan Burton
-
Henning Thielemann
-
Ryan Newton
-
Yitzchak Gale