I'm using Haskell openGL bindings to try to make a particle generator. I want to store information about a particle in a record where I can then pass in fields and update them when appropriate.
So a position in the record is stored as:
data Particle = Particle { pos :: Vertex2 GLfloat }
and set like this:
Particle { pos = Vertex2 1 (0::GLfloat) }
Then I pass in the particle and try to retrieve the values like so:
drawParticle :: Particle -> IO ()
drawParticle part =
(pos part) >>= \(Vertex2 x y) ->
print x
The error I get:
Couldn't match type `Vertex2' with `IO'
Expected type: IO GLfloat
Actual type: Vertex2 GLfloat
In the return type of a call of `pos'
In the first argument of `(>>=)', namely `(pos part)'
In the expression: (pos part) >>= \ (Vertex2 x y) -> print x
I'm mildly confused about the data type Vertex2 and why it has to be declared with a single GLfloat instead of two. How would I extract numbers from the data type Vertex2 GLfloat? (that is how would I extract Vertex2 1 (0::GLfloat) to be x = 1.0, y = 0.0?
To answer your questions:
It would be possible to define Vertex2 to take two types, to allow X to have one type and Y another, e.g. data Vertex2 xtype ytype = Vertex2 xtype ytype
. However, it's generally a bad idea to have two different types for X and Y so instead it's defined as: data Vertex2 sametype = Vertex2 sametype sametype
to save problems.
Since you have explicitly typed the Vertex2 in your declaration for Particle, you don't need to type the expression you list. Just Particle { pos = Vertex2 1 0 }
should be enough. (Or: Particle (Vertex2 1 0)
).
You get the compile error because you don't need monadic bind. part
has type Particle
, not IO Particle
, so you don't need bind to get the value out. You can write either:
drawParticle part = let Vertex2 x y = pos part in print x
or:
drawParticle part = do
let Vertex2 x y = pos part
print x
(Note the two different forms of let, depending on whether it's in a do
block; this confused me when I started out.)