Efficiency of using field labels vs pattern matching

Brian Hulley brianh at metamilk.com
Sun Aug 20 13:39:59 EDT 2006


Sigbjorn Finne wrote:
> If you let the Simplifier have a crack at your code (i.e., compile
> with -O or better), the same code should be generated for the two
> defns of 'foo'. Try compiling with -ddump-simpl to verify.

Thanks. I tried that and you're right. It also works well with an even more 
complicated example:

    data R = R{_xRef :: !(Ref.T Int), _y :: Int}

    foo :: Bool -> R -> IO ()
    foo b r = do
        if b
            then Ref.write (_xRef r) ((_y r) * (_y r))
            else return ()
        x <- Ref.read (_xRef r)
        print x

Even though there are 4 applications of field label functions and _y is not 
even a strict field, GHC -O2 manages to get both fields with a single case 
statement:

    Main.foo :: GHC.Base.Bool -> Main.R -> GHC.IOBase.IO ()
    [GlobalId]
    [Arity 3
        Worker Main.$wfoo
        Str: DmdType SU(U(L)L)L]
    Main.foo = __inline_me (\ (w_s2sp :: GHC.Base.Bool)
            (w1_s2sq :: Main.R)
            (w2_s2sy :: GHC.Prim.State# GHC.Prim.RealWorld) ->
            case (# GHC.Prim.State# GHC.Prim.RealWorld, () #) w1_s2sq
            of w3_X2sB { Main.R ww_s2ss ww1_s2sw ->

                -- well done GHC!!!! :-)

            case (# GHC.Prim.State# GHC.Prim.RealWorld, () #) ww_s2ss
            of ww2_X2sI { GHC.STRef.STRef ww3_s2su ->
            Main.$wfoo w_s2sp ww3_s2su ww1_s2sw w2_s2sy
            }
            })

This is great because some of my records have about 20 fields so the pattern 
matching was getting really cumbersome in the source.

BTW I made a module to make the IORef functions work with any MonadIO and 
also give them better names (to use by qualified import) which I enclose 
below if anyone is interested - I don't know where to put stuff like this:

----------------------------------------------------------------
-- |
-- Module: Prime.IORef
-- Author: Brian Hulley
-- License: Public Domain
--
-- Lifts (most of) Data.IORef to any MonadIO
-- This module should be used qualified so we can avoid
-- writing "IORef" everywhere
----------------------------------------------------------------
module Prime.IORef
    ( T
    , new
    , read
    , write
    , modify
    , weak
    ) where

    import Prelude hiding(read)
    import qualified Data.IORef as D
    import Control.Monad.Trans
    import System.Mem.Weak

    type T = D.IORef

    new :: MonadIO m => a -> m (T a)
    new x = liftIO $ D.newIORef x

    read :: MonadIO m => T a -> m a
    read x = liftIO $ D.readIORef x

    write :: MonadIO m => T a -> a -> m ()
    write x v = liftIO $ D.writeIORef x v

    modify :: MonadIO m => T a -> (a -> a) -> m ()
    modify x f = liftIO $ D.modifyIORef x f

    weak :: MonadIO m => T a -> m (Weak (T a))
    weak r = liftIO $ D.mkWeakIORef r (return ())

Regards, Brian.

-- 
Logic empowers us and Love gives us purpose.
Yet still phantoms restless for eras long past,
congealed in the present in unthought forms,
strive mightily unseen to destroy us.

http://www.metamilk.com 



More information about the Glasgow-haskell-users mailing list