
Hi, I'm designing an API for a simple graphics window, and am trying to make the correct usage of the API functions explicit and visible to the type system by using different monads which ultimately just wrap the IO monad. For example, in a callback for rendering stuff to the screen, only operations in the RenderM monad are allowed, and when specifying vertex info for a primitive, only VertexM operations are allowed. However I'm wondering if I can rely on all this monad stuff being optimized out at compile time. A sample monad is below: newtype VertexM a = VertexM (IO a) instance Monad VertexM where VertexM x >>= fry = VertexM $ do ax <- x let VertexM y = fry ax y return x = VertexM $ return x instance MonadIO VertexM where liftIO = VertexM The monad doesn't do anything interesting apart from allowing the type checker to reject programs that don't use the API the way it was intended (all these things you have to keep in your head in C programs), but I don't want to use it if I'm going to get a performance hit. Also, in: foreign import ccall duma_vertex3f :: Float -> Float -> Float -> IO () vertex3f :: Float -> Float -> Float -> VertexM () vertex3f x y z = liftIO $ duma_vertex3f x y z is there a penalty involved in calling vertex3f (from another module) or will the worker/wrapper optimization ensure that machine code in the other module just calls duma_vertex3f directly since the liftIO operation is just an irrelevance at the machine code level? So far I've just been using ghc --make and not bothering about what kind of code is generated. Is there a flag I can use to get ghc to output the stg code (or something higher level than just x86 machine code itself) so I can look at the output to see what optimizations are being done? Thanks, Brian.