
On Tue, May 24, 2011 at 08:54:05PM +1000, Arlen Cuss wrote:
Hi all,
I may be a liiittle in over my head. I'm trying to make a type-class for a type that can be "randomly generated". The class looks like this:
class RandomlyGeneratable a where rgen :: IO a
So far so good. Now, I'd love to be able to define an instance of this on all types that have Enum, because the definition is not hard:
instance Enum a => RandomlyGeneratable a where rgen = fmap (opts !!) $ randomRIO (0,pred (length opts)) where opts = enumFrom $ (toEnum 0) :: a
Unfortunately I'm wording this incorrectly, as the "instance" line produces:
Illegal instance declaration for `RandomlyGeneratable a' (All instance types must be of the form (T a1 ... an) where a1 ... an are *distinct type variables*, and each type variable appears at most once in the instance head. Use -XFlexibleInstances if you want to disable this.) In the instance declaration for `RandomlyGeneratable a'
Actually there wasn't much wrong with your syntax here, it's just that the basic Haskell standard is quite rigid in terms of what sorts of instances are accepted. If you turned on the flag -XFlexibleInstances (which is quite uncontroversial and widely supported) as the error message suggests, it would work fine. However, with this instance you would not able to make any other RandomlyGeneratable instances -- essentially the instance says "any type a is an instance of RandomlyGeneratable, and it is an error if the type a is not an instance of Enum". So for that reason the newytpe approach (what you wrote in your second email) is to be preferred. By the way, such a class already exists -- it is called Random [1]. But if you are just doing this as a learning exercise, then go right ahead. -Brent [1] http://hackage.haskell.org/packages/archive/random/latest/doc/html/System-Ra...