问题
I am working on an Asteroid game made in Haskell with Graphics.gloss. Now I have defined a datatype for the asteroids like this:
data Asteroid = Asteroid { asteroidPos:: Point,
asteroidVel :: Vector,
asteroidSize :: Float }
So that it has a Position defined by a point, a velocity defined by a vector and it's size. Now I want to know how I could write an instance of Random for this datatype so that a new asteroid appears at a random time, on a random place with a random velocity. Does anyone know how I can accomplish this?
回答1:
There's already a Random instance for Float. Assuming that you also have Random instances for Vector and Point, you can use them to define a Random instance for Asteroid:
instance Random Asteroid where
randomR (Asteroid pl vl sl, Asteroid ph vh sh) g =
let (p, g1) = randomR (pl, ph) g
(v, g2) = randomR (vl, vh) g1
(s, g3) = randomR (sl, sh) g2
in (Asteroid p v s, g3)
random g =
let (p, g1) = random g
(v, g2) = random g1
(s, g3) = random g2
in (Asteroid p v s, g3)
The randomR function takes a range of values, from minimum (low) to maximum (high). How you define a meaningful range of a complex value like Asteroid, I'll leave up to you; here, I'm simply assuming that you can pass a low and high Asteroid value.
The first step uses the underlying Random instance for Point by calling randomR. p is a randomly generated Point value, and g1 is the next random generator value to use.
Likewise, v is a randomly generated Vector value, generated by the underlying instance for Vector.
Finally, s is a Float generated by randomR for Float.
The return value is a new Asteroid value composed from p, v, and s, plus the most recent generator g3.
The implementation of random follows the same template.
You could write this code in a prettier form, using e.g. using MonadRandom, but for starters, I left the code in its raw form to show how it works.
来源:https://stackoverflow.com/questions/47133198/haskell-random-instance-of-own-datatype