
Bernd Brassel wrote:
* I'm not sure if you care whether they are performed once or many times. E.g. f = \x. x + unsafePerformIO (h z) If the (h z) doesn't mention 'x', GHC will transform this to v = unsafePerformIO (h z) f = \x. x+v So now the effect happens once only, rather than once per call of f. Again you can control this by adding an articifical dependency on x.
This is a very good example. The effect has to happen once per call to f.
So what do you mean by "adding an artificial dependency"? Would for this example something like the following be enough?
f = \x. x + myEffect x
myEffect _ = unsafePerformIO (h z)
Adding these artificial dependencies may amount to exactly the kind of effect analysis that Joesef suggests.
Yes such a determinism analysis is a good idea to optimize functional logic programs and we have already done work in that direction. But I would not like to turn those programs into a monad which we cannot prove to be deterministic. Your hint of "adding artificial dependencies" sounds more promising.
perhaps unsafePerformIODependingOn :: dep -> IO a -> a {-# NOINLINE unsafePerformIODependingOn #-} --is that pragma enough to avoid strictness/unused-ness analysis? --use 'lazy'? compile the module this is defined in with -O0? --I don't think seq'ing dep is desired. unsafePerformIODependingOn dep a = unsafePerformIO a f = \x. x + unsafePerformIODependingOn (x) (h z) --use a tuple if there are multiple variables you depend on also, do you care if the same `unsafePerformIO` is repeatedly performed more than once for no reason? Isaac