I'm trying to learn Haskell in the most "Haskell way" possible, so I'm trying to avoid things like dos and lets that sort of obscure what's actually going on.
So I have a data type called Org that in is defined as so:
data Org = Org
{ pos :: Pos2D
, color :: Color
} deriving (Show)
where Color and Pos2D are defined as so:
-- Not actually defined like this, it's Graphics.Gloss.Data.Color
data Color = Color Float Float Float Float
data Pos2D = Pos2D Float Float
Now I've implemented UniformRange for Pos2D and Uniform for Color as so:
instance UniformRange Pos2D
where
uniformRM (Pos2D x1 y1, Pos2D x2 y2) g = Pos2D
<$> uniformRM (x1, x2) g
<*> uniformRM (y1, y2) g
instance Uniform Color
where
uniformM g = G.makeColor
<$> uniformRM (0.0, 1.0) g
<*> uniformRM (0.0, 1.0) g
<*> uniformRM (0.0, 1.0) g
<*> return 1.0
Given a tuple of Pos2D (representing the corners of the bounds), it will return a random Pos2D distributed uniformly between those. And for Color, it will return a random color with uniform R, G, and B values, but with a fixed alpha = 255 (1.0).
The question is now, how do I make an org?
randomOrg :: RandomGen g => g -> Org
randomOrg = -- ...
where
gen = mkStdGen 1337
The issue I'm having is that uniformR and uniformM take a g and return a tuple of (a, g). So I'm not sure what the cleanest, most "Haskelly" way would be to actually chain these calls together to create the Org.
Any thoughts? Thanks,
Edit:
I know that I can do this:
randomOrg :: RandomGen g => g -> Org
randomOrg g = Org pos color
where
(pos, g1) = uniformR (Pos2D 0 0, Pos2D 720 480) g
(color, g2) = uniform g1
But I'm not a fan of that for obvious reasons.
Edit 2:
Ok so after some thinking, I think the function I need might need to look something like this?
pUniform
:: (Uniform a, RandomGen g)
=> (a -> b, g) -> (g -> (a, g)) -> (b, g)
But I'm not sure.
Edit 3:
Now I'm thinking a functor might be relvant:
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
So if we take some function (a->b) (which could be for example the Org constructor), and we have some a wrapped in the context f, which would be like (a, g) then we can produce a b wrapped in the context, which would be (b, g). Seems right to me, but I'm not sure how to translate that into actual code.