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 

    Main.foo :: GHC.Base.Bool -> Main.R -> GHC.IOBase.IO ()
    [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.


More information about the Glasgow-haskell-users mailing list