
Greetings Haskellers, I have recently found myself in a situation where I was needing to general tuples of randomized things; in my case, two coordinates and a custom data type, Direction. As it is always better to generalize, I decided to try to write some code which would generalize randomR to any type which is Ix-able:
instance Ix i => Random i where random = error "No supported instance for random" randomR r g = let r' = range r (i, g') = randomR (0,length r'-1) g in (r' !! i, g')
This works splendidly; with my given example above, I could do:
data Dir = N | NE | E | SE | S | SW | W | NW deriving (Eq, Ord, Show, Ix)
ghci> newStdGen >>= print . take 10 . randomRs ((1,1,N),(10,10,NW)) [(5,4,S), (3,10,SE), (6,5,N), (6,6,NW), (10,8,SE), (3,10,W), (10,3,E), (1,6,NE), (10,10,SE), (3,3,S)] As you can see, this results in random tuple(s) of these indexable types. My implementation required -fallow-overlapping-instances and - fallow-undecidable-instances for the code to compile. A few questions: 1) How does the compiler determine how to choose a particular instance for those cases where they overlap? I noticed that if I tried to generate a random :: Int, I was getting the error message defined in the above instance, indicating that the compiler was choosing my implementation over the default for Int (obviously because Int is an instance of Ix). Is there some way to exclude classes in the class qualifier, or to provide an instance as a default case without resorting to -fallow-overlapping-instances? 2) Is there a logical overlap between class Ix and class Bounded? It seems that we could use the ranges of data types of Bounded to generate a reasonably sane `random` implementation for all Ix, if we can guarantee that all Ix instances are Bounded. Would adding an additional class constraint be sufficient to catch the major cases? i.e., instance (HasBounds i, Ix i) => Random i where ... 3) Is there some reason that Ix is restricted to the Int datatype? Is there anything preventing us from moving to a genericIx,or something along those lines which support any integral type (say Integer), or is it merely for performance reasons that we use Int? Is the expectation that if you are using spaces larger than what an Int can accommodate, you should be using a different mechanism? Thanks much for any comments you all can give. Cheers, Lambda the Insignificant