
That's an interesting statement that bears further scrutiny. I've been viewing monads as a kind of encapsulation in a quasi-hidden world state. Yes a monad is a function that would give you an output if you had access to the input world. That is the picture drawn in Simon Peyton Jones' tutorial. I've been thinking of actions in terms of the functions x -> IO(a), but Simon calls these IO actions and calls monads actions as you do. Is it your claim that whenever an 'IO action' is performed on something like IO (x) with x <- newListArray a l that the newListArray function will be called ? So with the old paradigm, where Rmatrix was stored as (Int, Int, IO(StorableArry Int CDouble)). A typical matrix operation, that calls out to a BLAS C routine cside_effect() looks something like this under the old scheme matfunc A = (u,v, arr) where u = f1 (getrows A) (getcols B) v = f2 (getrows A) (getcols B) arr = do arrA <- getarr A withStorableArray arrA (\vara -> cside_effect vara ) return arrA Now when one uses this code do A <- getAfromSomewhere fA = matfunc A B <- anotherfunc A fA has been changed by the cside_effect function, but A has not! Is it your contention that the array in A is essentially copied or created anew for every getarr A call? I think getarr A looked something like getarr (Rmatrix (r,c,arr)) = arr in the old technique, but now looks like getarr (Rmatrix (r,c,arr)) = return arr Is this perhaps an effect of lazy evaluation? When does one actually need to evaluate the constructor for the storable array contained in A? Hmmm. Is it that the rules specify that an IO action forces the evaluation of the value in the monad, but otherwise this value may be unevaluated? So return x doesn't evaluate x but (return x)
= \z -> IOfunc z does?
This would actually make sense in the end. The IO action of A <- getAfromSomewhere would not evaluate the monad that is the third element of the tuple A, since there is no real 'need' to do so. So in fact no constructor of A's array would ever get evaluated until a function was applied to it, which would have to be in the form of an IO action. That's a nice mind twister. Clean's uniqueness types are a little easier to grasp I think. Ahh I think I understand now. It has to work that way or else you cannot guarantee the sequential execution property of monads. Thus if y :: IO (a) and you evaluate z <- func (f1 y) (f2 y), the evaluation order of y is controlled by what is implemented in func (and f1 and f2), not by evaluation rules for arguments. The value wrapped in y MUST remain unevaluated until IO 'actions' are performed on it. Brian Hulley wrote: this is not correct. IO (StorableArray Int CDouble) is a monadic *value* itself, which represents an *action* which returns a storable array, and since you are filling in the slot in Rmatrix with the action (newListArray a l), this monadic value represents the action of creating a new array whenever the action is executed.