James White has noticed that the draft Haskell 98 report gives the following translation for do-notation: do {e} = e do {e;stmts} = e >> do {stmts} do {p <- e; stmts} = let ok p = do {stmts} ok _ = fail "..." in e >>= ok On the face of it, that makes do-notation depend on the definitions of both (>>) and (>>=) in the monad. This makes a difference if someone defines an instance of the Monad class in which (>>) is not defined to be (\x y -> x >>= \_ -> y). I am certain that was not the intention of the authors. So one possibility is to change the second line to read do {e;stmts} = e >>= (\ _ -> do {stmts}) and that is what I *propose* to do. However, James implies that in his monad (>>) has a different meaning than its usual one, and Haskell 98 allows that because (>>) is one of the class operations (not a good design choice I think). I'm quite reluctant to make the meaning of do-notation dependent on such differences. James, can you convince us that doing so would be a good idea? Simon
Simon Peyton-Jones wrote:
However, James implies that in his monad (>>) has a different meaning than its usual one, and Haskell 98 allows that because (>>) is one of the class operations (not a good design choice I think). I'm quite reluctant to make the meaning of do-notation dependent on such differences. James, can you convince us that doing so would be a good idea?
I didn't see this before sending off my previous rant. My apologies. Having separate definitions for ">>=" and ">>" is more flexible. With the definition of a default for ">>" in the Monad class, having them separate is no less convenient. More flexible, no less convenient---where is the design flaw? I thought it was a design triumph, fully in the spirit of elegance I associate with Haskell. Are there Monad laws that this breaks? If not, why impose an unnecessary constraint? Let me describe my practical motivation for a separate definition for ">>". I am experimenting with using Haskell to build program generators for embedded domain-specific languages. The goal is to generate high-performance Fortran codes from high-level specifications. I am using a Monad to hold the state of the generation. One thing maintained in the state is a list of declared variables and a list of busy, or in-scope, variables. The generator automatically adds variable declarations as needed. By differentiating between monadic statements that return an argument (>>=) and those that don't (>>), the generator can easily determine when variables go out of scope. Within the definition of ">>", it can free these variables (in a logical, not physical, sense) to be reused. This is critical because it allows me to generate code using large temporary arrays efficiently. As far as I can tell, this use of ">>" breaks no monad laws. In Hugs, it works fine if I use ">>" directly instead of "do". For the aesthetic acceptance of my user base, I need it to work with "do" notation. -- James B. White III (Trey) Center for Computational Sciences Oak Ridge National Laboratory whitejbiii@ornl.gov
I am certain that was not the intention of the authors. So one possibility is to change the second line to read
do {e;stmts} = e >>= (\ _ -> do {stmts})
and that is what I *propose* to do.
However, James implies that in his monad (>>) has a different meaning than its usual one, and Haskell 98 allows that because (>>) is one of the class operations (not a good design choice I think). I'm quite reluctant to make the meaning of do-notation dependent on such differences.
I disagree. Hugs should be changed, not the report. In my opinion (>>) is a class operation, because there may be more efficient implementations of (>>) than the default one (\x y -> x >>= \_ -> y). The do notation should profit from a more efficient implementation. I do think that James steps on very dangerous ground if his implementation of (>>) is semantically different from (\x y -> x >>= \_ -> y). This semantic equality is a law of the monad class, that users expect to hold. However, the language (implementation) cannot enforce it; in particular, compilers cannot use such laws for optimisations. The programmer has the freedom to break such laws. The situation is similar with classes such as Eq and Ord. You expect x /= y == not (x == y), but it is not enforced. Actually, the report currently doesn't say that the given default definitions are laws which are expected to hold (except where a comment says otherwise, see class Enum). I think such a statement should be added to the report. Happy Easter, Olaf -- OLAF CHITIL, Dept. of Computer Science, The University of York, York YO10 5DD, UK. URL: http://www.cs.york.ac.uk/~olaf/ Tel: +44 1904 434756; Fax: +44 1904 432767
Olaf Chitil wrote:
I am certain that was not the intention of the authors. So one possibility is to change the second line to read
do {e;stmts} = e >>= (\ _ -> do {stmts})
and that is what I *propose* to do.
However, James implies that in his monad (>>) has a different meaning than its usual one, and Haskell 98 allows that because (>>) is one of the class operations (not a good design choice I think). I'm quite reluctant to make the meaning of do-notation dependent on such differences.
I disagree. Hugs should be changed, not the report. In my opinion (>>) is a class operation, because there may be more efficient implementations of (>>) than the default one (\x y -> x >>= \_ -> y). The do notation should profit from a more efficient implementation.
I agree with Olaf (and James). Incidentally, similar concerns occur in the context of the arrows framework. Ross Paterson, in response to a request from us at Yale, recently changed some derived arrow combinators into default methods of the arrow classes in his implementation of the framework to allow more efficient, instance specific, implementations of these combinators. Our request was prompted by our work of (A)FRP, an embedded language. /Henrik -- Henrik Nilsson Yale University Department of Computer Science nilsson@cs.yale.edu
On Thu, Mar 28, 2002 at 11:48:25AM -0500, nilsson@cs.yale.edu wrote:
Incidentally, similar concerns occur in the context of the arrows framework. Ross Paterson, in response to a request from us at Yale, recently changed some derived arrow combinators into default methods of the arrow classes in his implementation of the framework to allow more efficient, instance specific, implementations of these combinators. Our request was prompted by our work of (A)FRP, an embedded language.
Yes, but in that case the specific implementations are required to be denotationally equal to the default versions. And surely that was the original intention here. Section 6.3.6 of the Report needs an additional equation: m >> k = m >>= \_ -> k Then Hugs and GHC would be correct but suboptimal. There's a similar glitch in the claim in section 3.5 of the Report that (+ (- exp)) is a substitute for (\x -> x - exp), which is true only if x - y = x + negate y In that case the claim could be simply dropped.
Ross Paterson wrote:
Yes, but in that case the specific implementations are required to be denotationally equal to the default versions. And surely that was the original intention here. Section 6.3.6 of the Report needs an additional equation:
m >> k = m >>= \_ -> k
Then Hugs and GHC would be correct but suboptimal.
I agree that this equation should be in the report, but note that there is no *requirement* that the monad laws hold for user defined instances. The report merely states that they *should* hold. Maybe we should be more clear what this word *should* means. I understand it as meaning that the term "monad" suggests that these laws hold, that a programmer should have very good reasons for breaking any of them and if a law is broken a big warning should be attached to the code, because any user of a monad expects it to fulfill the laws. However, because the laws cannot be checked by an implementation, no implementation is allowed to make use of them. In particular, the laws may accidentally have been broken and if an implementation makes use of the laws, then the behaviour of the resulting computation may be completely incomprehensible. (Just to make clear that I don't advocate breaking these laws; but then I'm not a fan of monads anyway...) Olaf -- OLAF CHITIL, Dept. of Computer Science, The University of York, York YO10 5DD, UK. URL: http://www.cs.york.ac.uk/~olaf/ Tel: +44 1904 434756; Fax: +44 1904 432767
Yes, but in that case the specific implementations are required to be denotationally equal to the default versions.
Yes, obviously. My only point was that I believe (>>) should remain a class operation. /Henrik -- Henrik Nilsson Yale University Department of Computer Science nilsson@cs.yale.edu
participants (5)
-
James B. White III (Trey) -
nilsson@cs.yale.edu -
Olaf Chitil -
Ross Paterson -
Simon Peyton-Jones