
Hello all, Here's an experience report for porting hoopl to manage MonoLocalBinds. The Compiler.Hoop.XUtil module has a rather interesting (but probably common) style of code writing, along the lines of this: fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block where f n = FF3 $ ff n m n = FF3 $ fm n l n = FF3 $ fl n FF3 f `cat` FF3 f' = FF3 $ f' . f f, m, l and cat are polymorphic functions that are only used once in the main expression, and are floated outside to improve readability. However, when MonoLocalBinds is turned on, these all become monomorphic and the definitions fail. In contrast, this (uglier) version typechecks: fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 . fm) (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block One suggestion that I had was that we should generalize local bindings that are only used once, but Marlow pointed out that this would make the typechecker more complex and I probably would agree. As a userspace developer, I have two options: 1. Bite the bullet and put in the polymorphic type signatures (which can be quite hefty) 2. Inline the definitions 3. Move the polymorphic functions into the global namespace (3) and (2) are not so nice because it breaks the nice symmetry between these definitions, which always define f, m, l for the many, many definitions in Hoopl of this style. Cheers, Edward

Yes, argument to higher rank functions are probably the top reason why MonoLocalBinds is a nuisance. As of now I think the best thing is to do (1), but define type synonyms that abbreviate the oft-repeated signatures. That should make the signatures much onerous. Simon | -----Original Message----- | From: Edward Z. Yang [mailto:ezyang@MIT.EDU] | Sent: 09 December 2010 15:28 | To: glasgow-haskell-users; Simon Peyton-Jones | Subject: MonoLocalBinds and hoopl | | Hello all, | | Here's an experience report for porting hoopl to manage MonoLocalBinds. The | Compiler.Hoop.XUtil module has a rather interesting (but probably common) | style of code | writing, along the lines of this: | | fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) | block | where f n = FF3 $ ff n | m n = FF3 $ fm n | l n = FF3 $ fl n | FF3 f `cat` FF3 f' = FF3 $ f' . f | | f, m, l and cat are polymorphic functions that are only used once in the | main expression, and are floated outside to improve readability. However, | when | MonoLocalBinds is turned on, these all become monomorphic and the definitions | fail. In contrast, this (uglier) version typechecks: | | fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 | . fm) (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block | | One suggestion that I had was that we should generalize local bindings that | are only used once, but Marlow pointed out that this would make the | typechecker | more complex and I probably would agree. | | As a userspace developer, I have two options: | | 1. Bite the bullet and put in the polymorphic type signatures (which | can be quite hefty) | 2. Inline the definitions | 3. Move the polymorphic functions into the global namespace | | (3) and (2) are not so nice because it breaks the nice symmetry between these | definitions, which always define f, m, l for the many, many definitions in | Hoopl of this style. | | Cheers, | Edward

Hello,
Another design-pattern which sometimes works pretty well is to
encapsulate commonly used polymorphic types in ordinary data-types
(i.e., use the rank-2 style). Then, the data-type constructors provide
a quick way to---essentially---write a type signature. It seems that
this should work well in combination with mono-bindings.
Unfortunately, I am not sure that this would work for HOOPL (I
haven't looked at the code in detail), so apologies if this is a
red-herring.
-Iavor
On Fri, Dec 10, 2010 at 4:52 AM, Simon Peyton-Jones
Yes, argument to higher rank functions are probably the top reason why MonoLocalBinds is a nuisance.
As of now I think the best thing is to do (1), but define type synonyms that abbreviate the oft-repeated signatures. That should make the signatures much onerous.
Simon
| -----Original Message----- | From: Edward Z. Yang [mailto:ezyang@MIT.EDU] | Sent: 09 December 2010 15:28 | To: glasgow-haskell-users; Simon Peyton-Jones | Subject: MonoLocalBinds and hoopl | | Hello all, | | Here's an experience report for porting hoopl to manage MonoLocalBinds. The | Compiler.Hoop.XUtil module has a rather interesting (but probably common) | style of code | writing, along the lines of this: | | fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) | block | where f n = FF3 $ ff n | m n = FF3 $ fm n | l n = FF3 $ fl n | FF3 f `cat` FF3 f' = FF3 $ f' . f | | f, m, l and cat are polymorphic functions that are only used once in the | main expression, and are floated outside to improve readability. However, | when | MonoLocalBinds is turned on, these all become monomorphic and the definitions | fail. In contrast, this (uglier) version typechecks: | | fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 | . fm) (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block | | One suggestion that I had was that we should generalize local bindings that | are only used once, but Marlow pointed out that this would make the | typechecker | more complex and I probably would agree. | | As a userspace developer, I have two options: | | 1. Bite the bullet and put in the polymorphic type signatures (which | can be quite hefty) | 2. Inline the definitions | 3. Move the polymorphic functions into the global namespace | | (3) and (2) are not so nice because it breaks the nice symmetry between these | definitions, which always define f, m, l for the many, many definitions in | Hoopl of this style. | | Cheers, | Edward
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

I ran into some more code like this, and I realized there was something pretty important: the majority of let-bindings do not have any free varaibles. They could very well be floated to the top level without having to make any source level changes. So maybe let should be generalized, if no free variables are captured. Some food for thought. Cheers, Edward Excerpts from Edward Z. Yang's message of Thu Dec 09 10:28:20 -0500 2010:
Hello all,
Here's an experience report for porting hoopl to manage MonoLocalBinds. The Compiler.Hoop.XUtil module has a rather interesting (but probably common) style of code writing, along the lines of this:
fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block where f n = FF3 $ ff n m n = FF3 $ fm n l n = FF3 $ fl n FF3 f `cat` FF3 f' = FF3 $ f' . f
f, m, l and cat are polymorphic functions that are only used once in the main expression, and are floated outside to improve readability. However, when MonoLocalBinds is turned on, these all become monomorphic and the definitions fail. In contrast, this (uglier) version typechecks:
fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 . fm) (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block
One suggestion that I had was that we should generalize local bindings that are only used once, but Marlow pointed out that this would make the typechecker more complex and I probably would agree.
As a userspace developer, I have two options:
1. Bite the bullet and put in the polymorphic type signatures (which can be quite hefty) 2. Inline the definitions 3. Move the polymorphic functions into the global namespace
(3) and (2) are not so nice because it breaks the nice symmetry between these definitions, which always define f, m, l for the many, many definitions in Hoopl of this style.
Cheers, Edward

That is an interesting thought. As it happens, each binding records what its free variables are, so it would not be hard to check whether all the free variables were top-level-bound. Of course, it would make the rule a bit more complicated. Rather than only top level bindings are generalised it would be only binding groups whose free variables are top-level are generalised Mind you, the rule is complicated already; for example bang-patterns are not generalised. So maybe this would be no worse. I must say I'm inclined to adopt this idea. Any comments from others? Simon | -----Original Message----- | From: Edward Z. Yang [mailto:ezyang@MIT.EDU] | Sent: 14 June 2011 14:04 | To: glasgow-haskell-users; Simon Peyton-Jones | Subject: Re: MonoLocalBinds and hoopl | | I ran into some more code like this, and I realized there was something | pretty important: the majority of let-bindings do not have any free varaibles. | They could very well be floated to the top level without having to make any | source level changes. | | So maybe let should be generalized, if no free variables are captured. | Some food for thought. | | Cheers, | Edward | | Excerpts from Edward Z. Yang's message of Thu Dec 09 10:28:20 -0500 2010: | > Hello all, | > | > Here's an experience report for porting hoopl to manage MonoLocalBinds. The | > Compiler.Hoop.XUtil module has a rather interesting (but probably common) style of | code | > writing, along the lines of this: | > | > fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block | > where f n = FF3 $ ff n | > m n = FF3 $ fm n | > l n = FF3 $ fl n | > FF3 f `cat` FF3 f' = FF3 $ f' . f | > | > f, m, l and cat are polymorphic functions that are only used once in the | > main expression, and are floated outside to improve readability. However, when | > MonoLocalBinds is turned on, these all become monomorphic and the definitions | > fail. In contrast, this (uglier) version typechecks: | > | > fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 . fm) | (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block | > | > One suggestion that I had was that we should generalize local bindings that | > are only used once, but Marlow pointed out that this would make the typechecker | > more complex and I probably would agree. | > | > As a userspace developer, I have two options: | > | > 1. Bite the bullet and put in the polymorphic type signatures (which | > can be quite hefty) | > 2. Inline the definitions | > 3. Move the polymorphic functions into the global namespace | > | > (3) and (2) are not so nice because it breaks the nice symmetry between these | > definitions, which always define f, m, l for the many, many definitions in | > Hoopl of this style. | > | > Cheers, | > Edward | >

On 14/06/2011 14:28, Simon Peyton-Jones wrote:
That is an interesting thought. As it happens, each binding records what its free variables are, so it would not be hard to check whether all the free variables were top-level-bound.
Of course, it would make the rule a bit more complicated. Rather than only top level bindings are generalised it would be only binding groups whose free variables are top-level are generalised
Mind you, the rule is complicated already; for example bang-patterns are not generalised. So maybe this would be no worse.
I must say I'm inclined to adopt this idea. Any comments from others?
I'd rather the rule were simple, but I don't feel that strongly about it. While we're in the area, do you feel inclined to implement this? http://hackage.haskell.org/trac/ghc/ticket/2357 it would clear up the problems with MonoPatBinds - unlike MonoLocalBinds, you can't use a type signature to extract yourself from a MonoPatBinds error, and that proposal resolves the problems nicely. Cheers, Simon
Simon
| -----Original Message----- | From: Edward Z. Yang [mailto:ezyang@MIT.EDU] | Sent: 14 June 2011 14:04 | To: glasgow-haskell-users; Simon Peyton-Jones | Subject: Re: MonoLocalBinds and hoopl | | I ran into some more code like this, and I realized there was something | pretty important: the majority of let-bindings do not have any free varaibles. | They could very well be floated to the top level without having to make any | source level changes. | | So maybe let should be generalized, if no free variables are captured. | Some food for thought. | | Cheers, | Edward | | Excerpts from Edward Z. Yang's message of Thu Dec 09 10:28:20 -0500 2010: |> Hello all, |> |> Here's an experience report for porting hoopl to manage MonoLocalBinds. The |> Compiler.Hoop.XUtil module has a rather interesting (but probably common) style of | code |> writing, along the lines of this: |> |> fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block |> where f n = FF3 $ ff n |> m n = FF3 $ fm n |> l n = FF3 $ fl n |> FF3 f `cat` FF3 f' = FF3 $ f' . f |> |> f, m, l and cat are polymorphic functions that are only used once in the |> main expression, and are floated outside to improve readability. However, when |> MonoLocalBinds is turned on, these all become monomorphic and the definitions |> fail. In contrast, this (uglier) version typechecks: |> |> fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 . fm) | (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block |> |> One suggestion that I had was that we should generalize local bindings that |> are only used once, but Marlow pointed out that this would make the typechecker |> more complex and I probably would agree. |> |> As a userspace developer, I have two options: |> |> 1. Bite the bullet and put in the polymorphic type signatures (which |> can be quite hefty) |> 2. Inline the definitions |> 3. Move the polymorphic functions into the global namespace |> |> (3) and (2) are not so nice because it breaks the nice symmetry between these |> definitions, which always define f, m, l for the many, many definitions in |> Hoopl of this style. |> |> Cheers, |> Edward |>
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

In case it wasn't clear, I'd very much be in favor of implementing this refinement. Cheers, Edward

On 14 June 2011 14:28, Simon Peyton-Jones
I must say I'm inclined to adopt this idea. Any comments from others?
This is something I suggested at the time you submitted "let should not be generalised". I'm in favour of it, and from personal experience believe that this will reduce the number of people burnt by MonoLocalBinds (already small) by a good percentage. Max

FWIW, I eventually started avoiding local lets that use no local variables as just a matter of style - it read more clearly most of the time to put them at the top level (or not use them some other way). (But maybe that was just that I'd been really overusing such local bindings before.) I don't see a problem with the proposed rule Unless hmm-- is there a time that a user would want, or expect, their local binding not to be generalized, and then be confused by this exception? On 06/14/11 09:28, Simon Peyton-Jones wrote:
That is an interesting thought. As it happens, each binding records what its free variables are, so it would not be hard to check whether all the free variables were top-level-bound.
Of course, it would make the rule a bit more complicated. Rather than only top level bindings are generalised it would be only binding groups whose free variables are top-level are generalised
Mind you, the rule is complicated already; for example bang-patterns are not generalised. So maybe this would be no worse.
I must say I'm inclined to adopt this idea. Any comments from others?
Simon
| -----Original Message----- | From: Edward Z. Yang [mailto:ezyang@MIT.EDU] | Sent: 14 June 2011 14:04 | To: glasgow-haskell-users; Simon Peyton-Jones | Subject: Re: MonoLocalBinds and hoopl | | I ran into some more code like this, and I realized there was something | pretty important: the majority of let-bindings do not have any free varaibles. | They could very well be floated to the top level without having to make any | source level changes. | | So maybe let should be generalized, if no free variables are captured. | Some food for thought. | | Cheers, | Edward | | Excerpts from Edward Z. Yang's message of Thu Dec 09 10:28:20 -0500 2010: |> Hello all, |> |> Here's an experience report for porting hoopl to manage MonoLocalBinds. The |> Compiler.Hoop.XUtil module has a rather interesting (but probably common) style of | code |> writing, along the lines of this: |> |> fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block |> where f n = FF3 $ ff n |> m n = FF3 $ fm n |> l n = FF3 $ fl n |> FF3 f `cat` FF3 f' = FF3 $ f' . f |> |> f, m, l and cat are polymorphic functions that are only used once in the |> main expression, and are floated outside to improve readability. However, when |> MonoLocalBinds is turned on, these all become monomorphic and the definitions |> fail. In contrast, this (uglier) version typechecks: |> |> fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock (FF3 . ff) (FF3 . fm) | (FF3 . fl) (\(FF3 f) (FF3 f') -> FF3 $ f' . f)) block |> |> One suggestion that I had was that we should generalize local bindings that |> are only used once, but Marlow pointed out that this would make the typechecker |> more complex and I probably would agree. |> |> As a userspace developer, I have two options: |> |> 1. Bite the bullet and put in the polymorphic type signatures (which |> can be quite hefty) |> 2. Inline the definitions |> 3. Move the polymorphic functions into the global namespace |> |> (3) and (2) are not so nice because it breaks the nice symmetry between these |> definitions, which always define f, m, l for the many, many definitions in |> Hoopl of this style. |> |> Cheers, |> Edward |>
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
participants (6)
-
Edward Z. Yang
-
Iavor Diatchki
-
Isaac Dupree
-
Max Bolingbroke
-
Simon Marlow
-
Simon Peyton-Jones