
On Wed, Aug 09, 2006 at 08:40:06AM +0100, Simon Peyton-Jones wrote:
What's the implementation you have in mind? It's sure to get in the way of some optimisations; e.g. ((\x.e) `dependingOn` y) arg Maybe that doesn’t matter. I'm reluctant to build in optimisation rules for dependingOn.
getting in the way of optimizations is 100% exactly the purpose of it. there are two optimizations in particular it gives the user fine grained control over, CSE and let floating. it is also very useful for implementing low level IO stuff, and some special case code in ghc dealing with the world# can be dropped probably if dependingOn were used. (I'll get to that)
Is the argument order right? dependingOn is very like "seq" except that it's lazy. Shouldn't it have the same type?
I think the similarity to seq is mainly superficial. seq doesn't actually keep its arguments coupled together, it causes its first argument to be strict in a given context, but other than that it doesn't really use its second argument. both evaluations can be floated around independently after the initial transformation. dependingOn maintains the relaionship between its arguments throughout the compilation process right up to code generation.
When is it ok to inline the function, to reveal its (lack of) implementation? Can you just implement it in a library of your own?
I am assuming it will be transformed into a primitive that is simply passed through the opimizer like normal and discarded by the code generator. the existing touch# might do the job.
Can you list the "all sorts of applications" you have in mind?
for the user there are a couple of uses, mainly it gets rid of the caveats of using unsafePerformIO so you no longer need to turn of let-floating or cse to use it safely in certain cases. -- no need for CSE
data Dummy1 = Dummy1 intVar1 :: IORef Int intVar1 = unsafePerformIO (newIORef 0 `dependingOn` Dummy1)
data Dummy2 = Dummy2 intVar2 :: IORef Int intVar2 = unsafePerformIO (newIORef 0 `dependingOn` Dummy2)
normally, you would have to compile with -fno-cse to keep these two variables from being turned into one. however, since Dummy1 and Dummy2 will never be the same, the two terms cannot be considered the same by he optimizer so there is no problem. -- no need for turning off let-floating f x = log `seq` ... where log = unsafePerformIO (putErrLn "f called" `dependingOn` x) normally, the log function will be floated out so the rouinte is only called once when you actually want it to be executed every time f x is entered. the 'dependingOn' ensures this is the case. similarly, it can be used to quash space leaks bigAndFast is something that is trivial to compute, but would take up a ton of space if kept around, like an expanded string. you want to ensure it is not floated to the top level. f x = ... bigAndFast ... where bigAndFast = unpackString (constantString `dependingOn` x) now it cannot be floated to the top level. Now for some of the low level goodness: right now, ghc has to be careful to never inline unsafePerformIO, this gets in the way of optimizations, like if what it computes is a good producer, you still can't fusion it with a consumer. -- current definition {-# NOINLINE unsafePerformIO #-} unsafePerformIO :: IO a -> a unsafePerformIO (IO m) = case m realWorld# of (# _, r #) -> r -- new definition unsafePerformIO :: IO a -> a unsafePerformIO (IO m) = case m (realWorld# `dependingOn` m) of (# _, r #) -> r now the problem goes away, realWord# is no longer a consant that might lead to CSEing with something else, but now depends on the argumen to unsafePerformIO. now unsafePerformIO can safely be inlined. similarly, runST and array creation can be simplified in the same way. it allows sequence points to be implemented, right now there is special case code in the compiler to ensure certain strict values are never floated 'ahead' in the IO monad. you can implement something like sequence :: a -> IO a sequence x = IO \world -> (# world, x `dependingOn` world #) now, any use of thunks passed through sequence are guarenteed to not be evaluated until after all IO actions happening before it have completed. other uses have popped up. I implemented it just as a hack to get array creation to work, but have found it to be very useful in general. John -- John Meacham - ⑆repetae.net⑆john⑈