
Brian I've committed a fix for this. By which I mean that you don't need to write dropRenderM. You can just use RenderM as if it were IO. The change won't be in 6.4.2, but it's in the HEAD and will be in 6.6 Simon | -----Original Message----- | From: glasgow-haskell-users-bounces@haskell.org [mailto:glasgow-haskell-users- | bounces@haskell.org] On Behalf Of Brian Hulley | Sent: 30 March 2006 03:50 | To: glasgow-haskell-users@haskell.org | Subject: Re: Possible runtime overhead of wrapping the IO monad? | | Brian Hulley wrote: | > With -O2 enabled, __ccall_GC duma_vertex3f is indeed called directly | > instead of vertex3f, from a different module, so that proves that | > different monads can indeed be used to wrap IO operations without any | > performance penalty at all. | | However I've just discovered there *is* a penalty for converting between | callback functions that return a different monad from the IO monad. For | example, if I have a RenderM monad that allows primitives to be drawn to the | screen, and a callback: | | newtype RenderM a = RenderM (IO a) deriving (Functor, Monad, MonadIO) | | type RenderCallback = Int -> Int -> RenderM () | | where the intention is that the callback will take the width and height of | the window and return a RenderM action, the problem is that because the FFI | does not allow RenderM to appear in a foreign type, the actual render | function has to be converted into a function which returns an IO action | instead of a RenderM action eg by: | | type RenderCallbackIO = Int -> Int -> IO () | | dropRenderM :: RenderCallback -> RenderCallbackIO | dropRenderM f x y = let RenderM io = f x y in io | | foreign import ccall duma_onRender :: FunPtr RenderCallbackIO -> IO | () | | foreign import ccall "wrapper" mkRenderCallbackIO | :: RenderCallbackIO -> IO (FunPtr RenderCallbackIO) | | onRender :: RenderCallback -> IO () | onRender f = mkRenderCallbackIO (dropRenderM f) >>= duma_onRender | | With -O2 optimization, GHC does not seem to be able to optimize out the call | to dropRenderM even though this just changes the return value of f from | RenderM (IO a) to IO a, so RenderM is not transparent after all: | | Duma.onRender = \ (f :: Duma.RenderCallback) | (eta :: GHC.Prim.State# GHC.Prim.RealWorld) -> | case (# GHC.Prim.State# GHC.Prim.RealWorld, () #) | Duma.mkRenderCallbackIO | (Duma.dropRenderM f) eta | of wild { (# new_s, a86 #) -> | case (# GHC.Prim.State# GHC.Prim.RealWorld, () #) a86 | of ds { GHC.Ptr.FunPtr ds1 -> | case (# GHC.Prim.State# GHC.Prim.RealWorld, | () #) {__ccall_GC duma_onRender GHC.Prim.Addr# | -> GHC.Prim.State# GHC.Prim.RealWorld | -> (# GHC.Prim.State# GHC.Prim.RealWorld #)} | ds1 new_s | of wild1 { (# ds2 #) -> | (# ds2, GHC.Base.() #) | } | } | } | | I must admit I'm not at all clear how to read the -ddump-simpl output so I | may have got this wrong, but since Duma.dropRenderM is mentioned, I think | this means this has not been optimized out. | | Therefore there does seem to be an overhead for using different monads at | the moment (?) | | Regards, Brian. | | _______________________________________________ | Glasgow-haskell-users mailing list | Glasgow-haskell-users@haskell.org | http://www.haskell.org/mailman/listinfo/glasgow-haskell-users