[Haskell] unsafePerformIO and optimizations

Wolfgang Jeltsch wolfgang at jeltsch.net
Sat Aug 6 10:23:58 EDT 2005



talks about what optimizations you should disable if you apply unsafePerformIO 
to an action which contains side effects.  These are:

    * inlining of functions which call unsafePerformIO

    * common subexpression elimination (on the module which contains the
      unsafePerformIO application, if I understand correctly)

    * let-floating

Alas, the documentation is very terse, in my opinion, and I don't understand 
these things fully.

First, what is the problem with inlining a function call?  Say, I have a 
function f defined as follows:

    f :: Char -> ()
    f c = unsafePerformIO (putChar c)

If inlining is allowed, the expression f '*' becomes

    unsafePerformIO (putChar '*').

Is this a problem?  Or is inlining dangerous in other situations?

On the other hand, I can see that inlining non-functions could cause harm.  
Say I have something like this:

    u :: ()
    u = unsafePerformIO (putChar '*')

Now, inlining u would transform (u,u) to 

    (unsafePerformIO (putChar '*),unsafePerformIO (putChar '*'))

which could result in putChar '*' being executed multiple times.  So why does 
the library documentation only talk about disabling inlining of functions?

I understand that common subexpression elimination could cause harm.  It could 
transform the expression

    (unsafePerformIO (putChar '*),unsafePerformIO (putChar '*'))


        u = unsafePerformIO (putChar '*')

couldn't it?  This would result in the I/O action be performed at most once 
which is not what was intended.  But couldn't the same thing also happen if I 
use the expression (f '*',f '*'), probably in a different module?  Does this 
mean that I have to use -fno-cse not only in the module which contains the 
unsafePerformIO application but also in every other module which uses 
unsafePerformIO indirectly via f or functions using f?

Does let-floating only have to be disabled in the module which uses 
unsafePerformIO?  Say, I have f defined as above and have the following 
definition in a module different from the one f is defined in:

    g :: Int -> ()
    g n = f '*'

Couldn't it be that the asterisk is output only once instead of every time, g 
is called?

I would be thankful for any help.

Best regards,
Haskell mailing list
Haskell at haskell.org

More information about the Glasgow-haskell-users mailing list