[GHC] #14527: Warn on recursive bindings

GHC ghc-devs at haskell.org
Sun Nov 26 12:07:26 UTC 2017


#14527: Warn on recursive bindings
-------------------------------------+-------------------------------------
        Reporter:  chrisdone         |                Owner:  (none)
            Type:  feature request   |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.2.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Description changed by chrisdone:

Old description:

> When you accidentally write something like `let x = .. x ...` it can take
> hours to realize where you made your mistake. This hits me once in a
> while, and my colleagues often.
>
> I'd propose e.g. `-Wrecursive-bindings` that says:
>
> {{{
> warning: [-Wrecursive-bindings]
>     Recursive binding for `x` in
>
>     let x = length x
> }}}
>
> This applies to `let`, `where` and top-level pattern bindings.
>
> I believe that in practice, I only actually use real recursive bindings
> once in a while. So I might be bold enough to encourage enabling it in
> `-Wall` for a future major GHC release.
>
> With the compromise that if you have the warning enabled but in one
> specific place, you want a recursive binding, you can use the `~` tilde
> to say "I really mean it", e.g.
>
> {{{let ~ones = 1 : ones}}}
>
> That seems like a nice balance to say "I know what I'm doing in this
> case". So the warning could be more helpful, like:
>
> {{{
> warning: [-Wrecursive-bindings]
>     Recursive binding for `ones` in
>
>     let ones = length ones
>
>     If intentional, use the tilde marker on the name like this:
>
>     let ~ones = length ones
>
> }}}
>
> In Intero if I were to implement a prototype of this check, I'd probably
> do this, after renaming:
>
> 1. Use SYB to collect all variable bindings from the pattern.
> 2. Use SYB to listify all mentions of any of these variables in the RHS
> and any guards or where clauses.
>
> If the list is non-empty, then trigger the error. A transformation
> function {{{[Name] -> Pat -> Pat}}} would provide the AST with the
> offending name(s) tilded as {{{~x}}} for use in the error message.
>
> If there's general agreement, I could implement this change.

New description:

 When you accidentally write something like `let x = .. x ...` it can take
 hours to realize where you made your mistake. This hits me once in a
 while, and my colleagues often.

 I'd propose e.g. `-Wrecursive-bindings` that says:

 {{{
 warning: [-Wrecursive-bindings]
     Recursive binding for `x` in

     let x = length x
 }}}

 This applies to `let`, `where` and top-level pattern bindings.

 I believe that in practice, I only actually use real recursive bindings
 once in a while. So I might be bold enough to encourage enabling it in
 `-Wall` for a future major GHC release.

 With the compromise that if you have the warning enabled but in one
 specific place, you want a recursive binding, you can use the `~` tilde to
 say "I really mean it", e.g.

 {{{let ~ones = 1 : ones}}}

 That seems like a nice balance to say "I know what I'm doing in this
 case". So the warning could be more helpful, like:

 {{{
 warning: [-Wrecursive-bindings]
     Recursive binding for `ones` in

     let ones = length ones

     If intentional, use the tilde marker on the name like this:

     let ~ones = length ones

 }}}

 In Intero if I were to implement a prototype of this check, I'd probably
 do this, after renaming:

 1. Use SYB to collect all variable bindings from the pattern.
 2. Use SYB to listify all mentions of any of these variables in the RHS
 and any guards or where clauses.

 If the list is non-empty, then trigger the error. A transformation
 function {{{[Name] -> Pat -> Pat}}} would provide the AST with the
 offending name(s) tilded as {{{~x}}} for use in the error message.

 If there's general agreement, I could implement this change.

 **EDIT**: mutually recursive bindings apply here too. So {{{let x = y; y =
 x}}} by a regular occurs check.

--

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14527#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list