Re: [Haskell-cafe] Linking to third party libraries in windows

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.

Matthew Bromberg wrote:
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.
The IO monad can be viewed as encapsulating a function from a world state to a pair consisting of an updated world state and a "return value" as follows: data IO a = IO (RealWorld -> (RealWorld, a))
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.
So the function is contained *inside* the representation of the IO action so it's IO (x -> (x,a)) not x -> IO a
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 ?
If I write: do let n = newListArray a l p <- n q <- n two separate arrays will be created, because n is the action of creating a new array, and this action is executed twice in the body of the do. However, if I instead wrote: do x <- newListArray a l let r = return x p <- r q <- r only one array would be created, and this would be shared between x, p, and q, because the action (newListArray a l) is now only executed once (x is the result of the action ie the array, not the action itself)
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?
matfunc A never actually calls getarr A. It just sets up a tuple where the 3rd element is an IO action that, when that 3rd element is actually executed, would execute the 3rd element of the original A, and pass the array that was returned by it to your C function, and then return that array. I think the essence of the confusion is that there are two kinds of actions that the 3rd element of A might be bound to: 1) An action which just returns an array that was previously created 2) An action which creates a new array and returns that And both of these have the same type!!! because all the type system knows is that these two actions "do something (maybe nothing) then return an array" Case 2 was what you were doing right at the beginning, when the 3rd element was (newListArray a l), and case 1 was what I pointed out you could have used ie using the action (return arr) where arr was allocated during the construction of Rmatrix.
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?
No. An action, when executed, returns a value, but this doesn't imply that all actions have values stored in them. Bulat's illustration of getChar is a perfect example of this, since getChar has type IO Char but does not store the Char inside it, and executing it multiple times will in general give different characters back depending on your input stream... However the action (return 'q') also has type IO Char but this time, the 'q' is stored inside the action (return 'q'). So it matters exactly what action it is, since they can't be distinguished just by looking at the types.
So return x doesn't evaluate x but (return x) >> = \z -> IOfunc z does?
If you executed (return x), what first happens is that the *function* return:: a-> IO a is applied to its argument value 'x' to get an *action* which, when executed, will be able to supply the result value x, then this action *is* executed, and x is available as the result. Depending on the particular monad, x may or may not be evaluated. AFAIK for the IO monad, it would not be, but I think it is possible to conceive of a monad where the return function would need to evaluate its argument. Also, even if x was unevaluated by it's journey through the return function and executed action which hands it onto the input of iofunc, iofunc may or may not evaluate it. The short answer is: lazyness is a separate issue. A longer answer (given near the end of the thread referenced below) is that it depends on the fact that evaluation never happens under a lambda ie \x -> exp prevents exp being looked at until the function is applied, and that the sequence operator >> is defined in terms of >>= so that the second action is always lifted into a function.
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.
You're *very* close to understanding it. You're right that in Haskell arguments are never evaluated eagerly by some generic evaluation rule - the function application is just replaced by the body of the function with that unevaluated argument expression replacing all occurrences of the argument variable ie lazy evaluation. You just need to distinguish between the concepts of evaluation and execution, so in your example above, where y has been bound to some expression that evaluates to an action, depending on func, f1, f2, the expression y is bound to may be evaluated zero or more times (depending on whether or not y is used polymorphically within the function(s)), and the resulting action(s) may be executed multiple times. Personally I found it easier to underastand monads by looking at a simple state monad first so it's very clear what is happening, because then you can look inside the implementation of >>= and return and see that these are just quite simple functions. It is impossible to understand monads just by considering the types alone. The IO monad is extremely tricky to fully understand because you can't see how it is implemented, and as explained above, the types are not enough to distinguish between quite different behaviours whereas a state monad reveals exactly what's happening. (There was a long discussion beginning http://www.haskell.org//pipermail/haskell-cafe/2006-May/015605.html about how best to understand IO but certainly before trying to do so, a state monad is *infinitely* easier to understand and then provides a good basis for understanding IO) The first monad I understood was the state monad on page 261 of Paul Hudak's book "The Haskell School of Expression", and there are also some tutorials on the wiki at http://www.haskell.org/haskellwiki/Books_and_tutorials#Using_Monads Regards, Brian. -- Logic empowers us and Love gives us purpose. But societal laws, and religious dogma, empower the dead, to destroy us. http://www.metamilk.com

Brian Hulley wrote:
If I write:
do let n = newListArray a l p <- n q <- n
two separate arrays will be created, because n is the action of creating a new array, and this action is executed twice in the body of the do.
However, if I instead wrote:
do x <- newListArray a l let r = return x p <- r q <- r
I should have used the word "executed" instead of "write" and "wrote". Regards, Brian.

Hello Brian, Sunday, May 28, 2006, 1:06:06 AM, you wrote:
how best to understand IO but certainly before trying to do so, a state monad is *infinitely* easier to understand and then provides a good basis for understanding IO)
The first monad I understood was the state monad on page 261 of Paul Hudak's
i can also point to paper: http://research.microsoft.com/users/simonpj/Papers/state-lasc.ps.gz and it's reduced variant: http://research.microsoft.com/users/simonpj/Papers/lazy-functional-state-thr... there's also well-known http://www.nomaware.com/monads/monad_tutorial.zip -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Bulat Ziganshin wrote:
Hello Brian,
Sunday, May 28, 2006, 1:06:06 AM, you wrote:
how best to understand IO but certainly before trying to do so, a state monad is *infinitely* easier to understand and then provides a good basis for understanding IO)
The first monad I understood was the state monad on page 261 of Paul Hudak's
i can also point to paper: http://research.microsoft.com/users/simonpj/Papers/state-lasc.ps.gz and it's reduced variant: http://research.microsoft.com/users/simonpj/Papers/lazy-functional-state-thr...
there's also well-known http://www.nomaware.com/monads/monad_tutorial.zip
Hi Bulat, Thanks for the links. I'm glad to see these are now also linked from the wiki at http://www.haskell.org/haskellwiki/Books_and_tutorials#Using_Monads and http://www.haskell.org/haskellwiki/Research_papers/Monads_and_arrows Best regards, Brian. -- Logic empowers us and Love gives us purpose. But societal laws, and religious dogma, empower the dead, to destroy us. http://www.metamilk.com
participants (3)
-
Brian Hulley
-
Bulat Ziganshin
-
Matthew Bromberg