|
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Component: Compiler Version: 6.12.3 | Keywords: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ This is a request for an adjustment of the syntax for the new recursive do notation. "rec { ... }" should parse/type check as an expression such that: {{{ mdo a <- getChar b <- f c c <- g b putChar c return b }}} can be written as {{{ do rec a <- getChar b <- f c c <- g b putChar c return b }}} at moment the closest you can get is ... {{{ t5 = do rec a <- getChar b <- f c c <- g b putChar c return b }}} it seems rec { ... } is a binding construct not an expression and therefore can not be used in the final position (or sole component) of a do block benefits - drop in replacement for mdo, that is the construct "do rec" becomes semantically and syntactically equivalent to the mdo notation - current layout is maintained (which is much neater) - I would argue that it is more intuitive dificulty - it seems to be a minor change?. related - this change seems to have been introduced as [http://hackage.haskell.org/trac/ghc/ticket/2798] somewhat surreptitiously (well, cought me by surprise, anyway.). == background == 6.12.1 introduced a change to the recursive do syntax [http://old.nabble.com/Update-on-GHC-6.12.1-td26103595.html] Instead of writing {{{ mdo a <- getChar b <- f c c <- g b putChar c return b }}} you would write {{{ do a <- getChar rec { b <- f c ; c <- g b } putChar c return b }}} A couple of issues about the change: - the new syntax spoils layout (see above) - migrating to the new syntax with the current limitation is non-trivial, requires analysis of code (in some cases). for the record ... {{{ > t2 = > do rec > a <- getChar > b <- f c > c <- g b > putChar c > return b > f = return . (const 'a') > g = return eg.lhs:23:6: The last statement in a 'do' construct must be an expression Failed, modules loaded: none. }}} -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 6.12.3 Keywords: | Difficulty: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Comment(by simonpj): The change was in fact explicitly highlighted in my email to the ghc-users list http://www.mail-archive.com/glasgow-haskell- [hidden email]/msg17406.html. The difficulty I see with your suggestion is that it requires arbitrary lookahead to resolve the ambiguity. And in any case, you can always use 'mdo', right? What's wrong with doing that? Simon -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 6.12.3 Keywords: | Difficulty: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Comment(by simonmar): Replying to [comment:1 simonpj]: > The change was in fact explicitly highlighted in my email to the ghc- users list http://www.mail-archive.com/glasgow-haskell- [hidden email]/msg17406.html. > > The difficulty I see with your suggestion is that it requires arbitrary lookahead to resolve the ambiguity. Perhaps I'm being stupid, but I can't see how it needs arbitrary lookahead. Could you explain that? > And in any case, you can always use 'mdo', right? What's wrong with doing that? well, we deprecated the `mdo` notation. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 6.12.3 Keywords: | Difficulty: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Comment(by simonpj): Well, at the moment a `rec {...}` block can't be the last statement in a `do`. But after talking to Simon I realise that we could change that, by adopting the following translation: {{{ do { ...; rec { ...; e } } ==> do { ...; rec { ...; res <- e }; return res } }}} Now if the initial "..." was empty we could write {{{ do rec {...} }}} as "guest" (Jack, perhaps) wants. Simon -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 6.12.3 Keywords: | Difficulty: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Comment(by simonpj): I'm adding Ross's recent email to this ticket since it is relevant. http://www.haskell.org/pipermail/glasgow-haskell- users/2010-June/018944.html Here it is verbatim. There's also an underlying semantic issue, which is not yet resolved. The GHC implementation of mdo (following Levent and John's paper) performs a dependency analysis on the statements in the mdo to apply mfix to the shortest possible subsegments of statements. For example, {{{ mdo a <- f b b <- g b c <- h b d <- k d return d }}} is translated to the equivalent of {{{ do (a,b) <- mfix $ \ (a,b) -> do a <- f b b <- g b return (a,b) c <- h b d <- mfix $ \ d -> d <- k d return d return d }}} As the User's Guide notes, the choice of segments can change the semantics with some monads. When rec was added to GHC, the implementation used the same code and thus also did automatic segmentation. The original idea of rec (in arrow notation) was that it would give the programmer direct control over these segments: the loop/mfix combinators would go wherever the programmer put a rec, but I didn't realize Simon had done it the other way until he mentioned it last October. So: * if rec is to continue to do automatic segmentation, it might as well be a modifier on the do keyword (though this would break backward compatibility of arrow notation), * but I want to argue against automatic segmentation, because I don't think the compiler should be making subtle changes to the program's semantics on its own. It would simplify the compiler a bit too. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 6.12.3 Keywords: | Difficulty: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Changes (by simonpj): * cc: ross@…, iavor.diatchki@… (added) Comment: Last comment from me: * I don't have a strong opinion about any of this recursive-do stuff. But I'd like it to be as easy to use, and as predicatable, as possible. * I am totally snowed under for the next few weeks * If anyone is willing to take change of driving this issue to a consensus, I'd gladly help implement the result. Simon -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:5> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 6.12.3 Keywords: | Difficulty: Os: Unknown/Multiple | Testcase: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Comment(by guest): I believe both requirements can be satisfied, restating the requirements: - simple syntax for mdo with automatic segmentation - user control of segmentation at first look the two requirements appear to be contradictory, however if we observe that there are two syntactically distinguished use cases for "rec" then perhaps there is room for satisfying both requirements. == Proposal == - as per suggestion made here, a translation could be applied, when a rec {...} block is the last statement in a do. In this case a and only in this case is a dependency analysis on the statements done in the mdo to apply mfix to the shortest possible subsegments of statements. - In the case when the rec appears within the body of a do and not in the above final position, follow the original idea of rec as stated by Ross. the loop/mfix combinators would go wherever the programmer put the rec what this achieves is - do rec {...} is recognised syntactically, and becomes a drop in replacement for mdo. - when do { ...; rec { ... } ...; } is used it follows the conventions stated by Ross, thereby providing the programmer with the desired control. cons - the cons are that some added complexity in tracking the application of said translation John. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:6> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: normal | Milestone: 6.16.1 Component: Compiler | Version: 6.12.3 Keywords: | Testcase: Blockedby: | Difficulty: Os: Unknown/Multiple | Blocking: Architecture: Unknown/Multiple | Failure: None/Unknown ---------------------------------+------------------------------------------ Changes (by igloo): * milestone: => 6.16.1 -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:7> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Changes (by lerkok): * cc: erkokl@… (added) -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:9> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by ryani): I would suggest never doing dependency analysis with rec (I was actually unaware that this happened and thought that was the whole point of migrating to 'rec' over 'mdo'). I second the suggestion that we translate {{{ do { ... ; rec { ...; e } } }}} (i.e. 'rec' as the last statement in a do block) into {{{ do { ... ; rec { ...; fresh <- e} ; return fresh } }}} And translate {{{ do rec { ... } }}} into {{{ do { rec { ... } } }}} -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:10> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by lerkok): Apologies for the rather long comment below. It's my personal view and I'm probably a bit biased towards the very original translation of mdo- expressions for historical reasons. I'm hoping others will find it useful in shedding some light onto at least the original motivations for the segmentation aspect of mdo, which seems to be the main source of discontent here.. Segmentation was part of the very original transformation proposed for mdo expressions for a very simple reason: The right-shrinking property of mfix only holds for very few monads of practical interest. Without right- shrinking, the knot-tying loop implied by mfix cannot be loosened on the right without changing termination properties. This aspect is well studied in the literature: In fact, there's a very generic theorem stating that no monad based on a disjoint sum type admits a value recursion operator that satisfies the right-shrinking property. (See proposition 3.1.6 of http://goo.gl/Dj6CO, for instance.) A similar concern arises in the context of traces over premonoidal categories, as found in Nick Benton's work, and also in Ross Patterson's arrow-fix axiomatization; for instance when one considers the fixed-point operator for he Kleisli arrow of a monad, as derived from the mfix of the underlying monad. The question then becomes what is the user intended meaning of such expressions, when used with a monad that doesn't satisfy the right- shrinking property? There's a rough analogy here with typing of recursive binding groups: When a recursive binding group is typed (i.e., a let/where expression), Haskell says that recursively dependent groups must be identified and typed separately. This improves polymorphism. If you don't do the grouping, then you'll get less polymorphic types. Not doing this would be confusing for the user, since seemingly irrelevant bindings in a group shouldn't change what types are assigned to other bindings. If you don't do this "segmentation" during typing, then you'll get less polymorphic types, which would be arguably not what the user wanted in the first place. We (John Launchbury and myself) had precisely the same motivation when the original mdo was designed: If there's a recursive binding group, then the "knot" should be tied over the minimal segment necessary to resolve the recursive binding. If you do not do this, then textually irrelevant recursive bindings can change the meaning of one another, which can be quite confusing for the user. (There's a simple example of this in Section 7.2.2 of http://goo.gl/Dj6CO.) So, in this sense, grouping of recursive bindings for typing purposes in ordinary let/where expressions and grouping of recursive segments in an mdo-expression serve the same purpose of capturing the alleged user intent as closely as possible. One valid argument against the above claim could be that the polymorphic type improvement is a change to the static semantics, while the segmentation in mdo is a change to the dynamic semantics. This is true. However, the point remains that language constructs should reflect what the user intends to say. Furthermore, I see no reason why an mdo expression should say that all the bindings should be in one big knot-tying loop; Just like I wouldn't expect GHC to wrap around one big call to "fix" around any purely recursive group of definitions. Recall that the good old "fix" is *the* mfix for the identity monad, and when we write a recursive "let" binding, we can consider it as an mdo-binding over the identity monad. Just like we'd fully expect to see separate fix'es around different recursive bindings when we write code in the identity monad implicitly provided by let/where bindings, I'd expect to see separate fix'es (i.e., mfix calls) when I happen to use some other monad. That is, I don't see why other monads should be discriminated, as compared to the identity monad. (The same line of thought would also say we should have just one "do" expression that handles both recursive and non-recursive variants, just like we do not have separate let/letrec expressions in Haskell. However, I think changing "do" into a construct that also handles recursion is unrealistic for practical reasons. In particular, due to shadowing, the change wouldn't be backwards compatible.) One possible compromise might have been the following: Keep both mdo- expressions (which will do segmentation), and "rec" segments, which will not do segmentation. Unfortunately, mdo was removed from GHC a while ago as Simon commented above; so bringing it back is probably out of question. Given that, I'd think we should simply let "rec" do the segmentation as it does currently, giving us the rough equivalence that we can replace "mdo" with "do rec" (modulo the issue with the last expression has to be indented appropriately), and keep the segmentation semantics present as implied by the original mdo. If the user really wants to control where recursion takes place, then he/she can insert explicit calls to mfix as appropriate. In other words, if "rec" doesn't do segmentation, then writing the corresponding "mfix" is probably not asking too much either, so we should maybe completely drop the whole "rec" business and just live with explicit mfix calls. Having said all this, I also think that most of this discussion is rather moot as well. I'm yet to see anyone bitten by whether mdo (or rec) does segmentation or not. I believe that segmentation is rather necessary purely from a language design point of view for doing the right thing, i.e., matching the user intended semantics. But it's not the end of the world if we go the other way. Bringing back the good old "mdo" expresions would make me happy, but I can't say that it's a high priority by any means. Again, apologies for the long post and thanks for reading through my personal account of the matter. To state my position on this matter, I think the best solution would be to bring back mdo-expressions with full segmentation, and keep "rec" as well, which doesn't do any segmentation. However, it sounds like bringing "mdo" back in GHC is quite unlikely, so I think "rec" should keep doing segmentation so we have at least the rough correspondence "mdo = do rec". -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:11> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Changes (by simonpj): * cc: ryani (added) * difficulty: => Unknown Comment: I believe that both Iavor and Ross advocate: * Revive the `mdo` keyword (enabled by `RecursiveDo`) * Make `mdo` perform dependency analysis / segmentation * Keep the `rec` keyword (enabled by `DoRec`) * Cease doing dependency analysis / segmentation for `rec` So `mdo` is clever and does the segmenting stuff, but `rec` says "do exactly what I say" which gives precise control if you need it. To me that seems simple, predictable, and makes everyone happy. I suppose that if we ''stop'' doing segmentation for `rec` some programs might change behaviour, but I bet they are very few. (Opinions, Ross, Iavor?) It seems a bit overkill to have two language flags for what is really one feature. An alternative would be to make them synonymous for now, and deprecate `DoRec` in favour of `RecursiveDo`. Opinions? As Iavor says this is not a big deal. But presumably Ryan had a reason for raising it. Simon -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:12> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by lerkok): Hi Simon, [Looks like Iavor and I (Levent) got confused for each other again; I should've explicitly put my name under that long message, my apologies.] I completely agree with the solution you've outlined: * Bring "mdo" notation back, which does all the analysis. (As it was implemented in GHC the first time.) * Keep "rec", which is a simple wrapper with mfix; no analysis. * Both features turned on with just one flag, @RecursiveDo@ being the obvious choice. There's one hiccup though: What happens if someone uses a "rec" block inside an "mdo"? I think it would be best if such uses were grammatically flagged as syntax errors: "rec" should only be available inside an immediately enclosing "do". Does that make sense? Thanks, -Levent. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:13> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by simonpj): Sorry Levent! If you use a `rec` inside an `mdo`, I think the `rec` should be moved around intact, just like any other `Stmt`. So the `mdo` does dependency analysis treating the `rec` as an atomic unit. Would anyone like to implement this? Not hard, I think. Simon -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:14> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by simonmar): Must we really have two versions of the same extension? This seems unnecessarily complex to me. Can't we just decide which one is the best and keep it? I thought `do rec` was supposed to make things simpler? -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:15> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by lerkok): [No apologies needed Simon; Iavor and I have been confused for each other several times before..] Regarding use of `rec` within `mdo`: My concern was more about the confusion it would create, and it seems unnecessary. However, supporting it like you described might be the easiest thing to do. Simon M: Regarding `do rec` simplifying things: My personal opinion is that this is not the case. In the original translation we've described and implemented in GHC, there was no mention of `rec` anywhere, presenting a simple construct for the user that did all the necessary analysis/translation. As I've described above and documented elsewhere, I think segmentation is a necessary part of the translation, and is analogous to the segmentation you perform when typing recursive binding groups to improve polymorphism. (The analogy is not exact, but motivation is the same.) I believe the `rec` keyword came into play when Ross implemented the arrow syntax with `proc` and `do`; which did not have an explicit recursive counterpart; thus also needing a `rec` form. Once he introduced that, it created an obvious clash with `mdo`, as they were seemingly doing the same thing. But as argued previously in this ticket, they are quite different, and I do believe a single `mdo` construct is more appropriate then `do` with user-marked `rec` sections. Individual opinions might of course differ, as evidenced by this whole thread. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:16> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by ross): Replying to [comment:10 ryani]: > I would suggest never doing dependency analysis with rec (I was actually unaware that this happened and thought that was the whole point of migrating to 'rec' over 'mdo'). > > I second the suggestion that we translate > > {{{ do { ... ; rec { ...; e } } }}} > > (i.e. 'rec' as the last statement in a do block) into > > {{{ do { ... ; rec { ...; fresh <- e} ; return fresh } }}} The two are connected. With segmentation, this will then be transformed to the equivalent of > {{{ do { ... ; rec { ... } ; fresh <- e ; return fresh } }}} which may have different semantics. Certainly it will feed back a smaller tuple. Without segmentation, you might not want to do that. I'd rather {{{rec}}} wasn't subject to segmentation, as that would be simpler and more predictable. Levent made an analogy with ordinary recursive definitions; I'd make one with the common reluctance to rely on the compiler for transformations that improve the big-O complexity, except that termination is a bigger deal. Unfortunately that change will cause some programs not to terminate, with no hint from the compiler. I expect (but cannot prove) that Simon's right that this is fairly rare though. Having done my bit to complicate GHC, I'm naturally somewhat in favour of maximal simplicity elsewhere, which would mean no segmentation, no moving final expressions out of rec, and no mdo. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:17> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by lerkok): Ross: Strictly speaking, we don't really even need `rec`. Without segmentation, the job of `rec` is so straightforward, I don't think asking people to call `mfix` directly would be a big stretch. Maybe we should do away with the whole thing. Termination is a big issue, and there's a theorem that says segmentation will always improve termination properties. More importantly, I do believe it reflects the user intention better: Two sub-recursive computations shouldn't impact each other provided they don't share any variables. Segmentation guarantees that. Without segmentation, you get unintended interference. However, to put things in perspective, removal of `mdo` isn't really going to impact a lot of folks. Those who need it can clearly work around the issues. So, maybe Ross has the right wisdom in suggesting to go with maximal simplicity. In that case, I'd say we should remove `rec` as well; as it adds very little to the whole story. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:18> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by simonpj): Now I really am confused. Here's the design space {{{ mdo rec rec (with without with segmentation) segmentation segmentation What ------------------------------------------------------ - - YES (A) GHC now YES YES - (B) SPJ proposal - YES - (C) Ross proposal? - - - (D) Levent proposal? }}} I proposed (B). Have I understood Ross and Levent's propsals aright? I thought segmentation was important? Why did we write all that code to put it in if it's hardly useful? -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:19> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#4148: improve new recursive do syntax
---------------------------------+------------------------------------------ Reporter: guest | Owner: Type: feature request | Status: new Priority: low | Milestone: 7.6.1 Component: Compiler | Version: 6.12.3 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: None/Unknown Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by lerkok): Simon: Regarding your question why segmentation was ever implemented in the first place, here's a concrete example that'll hopefully demonstrate why segmentation is an essential part of monadic recursion. Consider the following simple function: {{{ produce :: [Int] -> IO [Int] produce xs = return $ take 10 [1+x | x <- xs] }}} Clearly `produce` doesn't need to be in the IO monad, but that's besides the point. The crucial thing is that it represents some function doing IO before returning a result. (In a more realistic instance, for example, it can read the constant `10` it uses in the call to `take` from a configuration file; or perform some other similar IO action to implement some other behavior.) Let's also imagine a caller to this function, of the following form: {{{ run :: IO [Int] run = do rec xs <- produce (1:xs) return xs }}} For instance, `run` can be used to implement a recurrence based algorithm, by passing a variant of its result to itself. (Think Fibonacci, Hamming codes, etc; for example, where the computation of the "next" element requires some monadic action.) The above code will work just as expected today in GHC, with `run` evaluating to the list `[2..11]`. So far, everything is just fine. Now, consider the following version of `run`, which simply prints the length of the list before returning its result, but it is otherwise equivalent to `run` above: {{{ run2 :: IO [Int] run2 = do rec xs <- produce (1:xs) print $ length xs return xs }}} For instance, I could imagine adding that `print` statement as part of debugging my code; or doing some other useful computation based on the result of the call to `produce`. If you execute `run2` today in GHC, you'll find that it'll work just as you expect: It'll first print `10`, and then return the list `[2..11]`. '''Here's the problem:''' If you change the translation of `rec` so that it no longer performs segmentation, then `run2` will *diverge*. Why? Because the trailing computation in printing the length of the final list will interfere with the recursive computation. In more fancy terms, since the `mfix` for the IO monad (the good old fixIO) does not satisfy the right-shrinking law, the non-recursive computation in the `mfix` loop cannot be lifted out. This is a fundamental limitation of the IO monad: There's no `mfix` for it that satisfies the right-shrinking law. (Of course, IO is just one example, many other monads have the same issue.) So, what does this mean? In my mind, it really means two things: * The promised correspondence that {{{ mdo ... e }}} is the same as {{{ do rec ... e }}} only holds provided the `rec` translation performs segmentation. If we don't do segmentation, then the correspondence is no longer valid as exemplified above. * Segmentation is really an essential part of the `mdo` (or `do` `rec`) semantics, if I write {{{ do rec xs <- produce (1:xs) print $ length xs return xs }}} Whether I keep the `print` in there or not should change anything. But if you do not do segmentation, the presence of `print` '''will''' change the semantics, causing it to diverge. (Imagine how awkward it would be to insert a "debugging" printf inside your `mdo` or `do` `rec` block, only to have it diverge all of a sudden.) I'm hoping the above example will convince us that segmentation is an essential feature of recursive monadic bindings. Based on this, I think proposal B provides a good compromise since it brings back `mdo` with its original intent, while keeping `rec` simple. To summarize, I'd humbly suggest we should do a minor variant of your proposal B: * Bring back `mdo` with segmentation (as was originally implemented in GHC) * Change `rec` so it does ''not'' do segmentation * Furthermore, allow `rec` only inside an immediately enclosing `do` block; syntactically rejecting it inside an `mdo`. I think this proposal is in the spirit of the original work on recursive monadic bindings, while also keeping `rec` quite simple as favored by Ross and Ryan. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/4148#comment:20> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
| Powered by Nabble | Edit this page |
