
SevenThunders wrote:
Well it certainly requires some thought here. As I see it, I now have two reasonable choices. Either I pull all my matrix operations back inside the IO monad and avoid the matrix action as a matrix variable paradigm (due to the loss of referential transparency) or I devise some way to guarantee 'safety' and use unsafePerformIO. I suppose I can use a somewhat generalized version of safety where if I can guarantee that the order of operations doesn't matter to the final output then I'm OK. In this case if I can make it so that reording the computations only reorders the locations of my matrices on the stack, but otherwise doesn't affect the contents of the matrices I think I am golden.
I believe I got burned by following a nice tutorial interpretation of the IO monad as a way of carrying around an undeclared state variable, the world. But my little matrix IO variable is not just a world state with some matrix data in it, rather it appears to be a world state with a chain of unapplied function evaluations. This is due to laziness I believe. If I had a data structure that looked more like a world state with a reference to a variable in that world state, I could find a way to achieve my goals I think.
I know that you have already made your decision and moved on, but I think that there is still another alternative that you can consider: make an abstract interpreter for your matrix operations. The basic idea is to use the normal Num et. al. type classes to write your matrix calculations. However, instead of actually performing the calculations it instead builds a data structure that represents the calculations. You then 'interpret' the data structure in a separate function in the IO monad. The advantage of the approach is that you can pre-process the abstract data structure to recognize intermediate matrices that can be consumed without copying and other optimizations. The other advantage is that the matrix math itself doesn't need to be in the IO monad, only the interpretation, so you can use all the functional goodness when writing the matrix operations. I was going to whip up a small example, but I am pressed for time. So here is a post from Oleg that shows the idea. http://www.haskell.org/pipermail/haskell/2007-January/019012.html As usual his post is mind-expanding and probably a bit of overkill for your problem, but I was the best I could come up with, google was not my friend. You might have better luck (try "higher order abstract syntax" and "abstract interpretation" and go from there)