
On Thu, 2007-06-14 at 22:50 -0700, Stefan O'Rear wrote:
| unsafeLiftIO :: (Buffer -> IO Buffer) -> Builder | unsafeLiftIO f = Builder $ \ k buf -> inlinePerformIO $ do | buf' <- f buf | return (k buf')
which might be safe, since 'f buf' cannot float out of the lambda which binds 'buf', but still, all this stuff is inlined, something constant might get plugged in the place of buf and the result might be floated out to give us an even harder to find Heisenbug.
I think this is safe because of the continuation k. In the Builder monoid, the continuation takes the place of the IO state token that gets single threaded through everything.
That's only safe if every function which passes an initial continuation (runBuilder etc) is NOINLINE - exactly the sort of global requirement that is far too easy to break if not documented.
There is only runBuilder that passes an initial continuation so it doesn't seem that hard. As you know, having tried to tackle the same problem, the Builder monoid is optimised for speed rather than for cleanliness (though it does aim for correctness). Duncan