Opened 9 years ago

Closed 8 years ago

#4940 closed feature request (fixed)

Bad error message using poly pat bind with MonoPatBinds

Reported by: batterseapower Owned by:
Priority: normal Milestone: 7.2.1
Component: Compiler (Type checker) Version: 7.0.1
Keywords: Cc: martijn@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect warning at compile-time Test Case: typecheck/should_compile/T5302
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


This program:

foo :: a -> a
bar :: a -> a
(foo, bar) = (\x -> x, \y -> y)

main = print $ foo $ bar 1

Is trying to pattern-bind a polymorphic function. The error message is dreadful:

    Couldn't match expected type `t -> t1'
                with actual type `forall a. a -> a'
    The lambda expression `\ x -> x' has one argument one argument,
    but its type `forall a. a -> a' has none
    In the expression: \ x -> x
    In the expression: (\ x -> x, \ y -> y)

The issues are:

  1. It repeats itself: "one argument one argument"
  2. It is patently incorrect: the type forall a. a -> a DOES have one argument in the standard nomenclature
  3. It does not point the user towards the fix (-XNoMonoPatBinds)

Change History (6)

comment:1 Changed 9 years ago by simonpj

Status: newmerge

This fixes item (1)

Tue Feb  1 12:29:20 GMT 2011
  * Fix type checker error message
  See Trac #4940. We had a message
       The lambda expression `\ x -> x' has one argument one argument,
  repeating the "one argument" part.  Easy fix.

    M ./compiler/typecheck/TcMatches.lhs -4 +4

Please merge to stable branch -- and then leave the ticket open for (2),(3)

comment:2 Changed 9 years ago by igloo

Status: mergenew


comment:3 Changed 9 years ago by igloo

Milestone: 7.0.3

comment:4 Changed 9 years ago by MartijnVanSteenbergen

Cc: martijn@… added

I was going to report something similar but found this bug here, so will add myself to CC. The error message in GHC 7.0.3 is still cryptic; it took a while to figure out what the problem and the solution were. I found bug 2187 which has a longer discussion and has a broken link to the Haskell' page on this issue; the new link is

My use case for -XNoMonoPatBinds is this:

Like yallop in bug 2187, I am using TH to derive tuples with polymorphic elements. The size of the tuple returned is equal to the number of constructors in the datastructure the functionality is derived for. I'm not a big fan of TH functions generating and introducing names into the top-level scope because it breaks modularity. Top-level pattern bindings are a very attractive solution: they allow me to give the user full control over the naming. It also allows the user to ignore a specific element of the tuple if it's undesired, by using a wildcard.

Here is an example:

I understand the reason for MonoPatBinds, but I will miss them. :-) :-( Is there another way in which I can let the user handle the naming of multiple generated polymorphic values this easily? The only thing I can think of is to add an argument for the list of to-be-introduced names to the TH function.

comment:5 Changed 8 years ago by simonpj@…

commit 49dbe60558deee5ea6cd2c7730b7c591d15559c8

Author: Simon Peyton Jones <>
Date:   Tue Aug 16 10:23:52 2011 +0100

    Major improvement to pattern bindings
    This patch makes a number of related improvements
    a) Implements the Haskell Prime semantics for pattern bindings
       (Trac #2357).  That is, a pattern binding p = e is typed
       just as if it had been written
            t = e
            f = case t of p -> f
            g = case t of p -> g
            ... etc ...
       where f,g are the variables bound by p. In paricular it's
       ok to say
          (f,g) = (\x -> x, \y -> True)
       and f and g will get propertly inferred types
          f :: a -> a
          g :: a -> Int
    b) Eliminates the MonoPatBinds flag altogether.  (For the moment
       it is deprecated and has no effect.)  Pattern bindings are now
       generalised as per (a).  Fixes Trac #2187 and #4940, in the
       way the users wanted!
    c) Improves the OutsideIn algorithm generalisation decision.
       Given a definition without a type signature (implying "infer
       the type"), the published algorithm rule is this:
          - generalise *top-level* functions, and
          - do not generalise *nested* functions
       The new rule is
          - generalise a binding whose free variables have
            Guaranteed Closed Types
          - do not generalise other bindings
       Generally, a top-level let-bound function has a Guaranteed
       Closed Type, and so does a nested function whose free vaiables
       are top-level functions, and so on. (However a top-level
       function that is bitten by the Monomorphism Restriction does
       not have a GCT.)
         f x = let { foo y = y } in ...
       Here 'foo' has no free variables, so it is generalised despite
       being nested.
    d) When inferring a type f :: ty for a definition f = e, check that
       the compiler would accept f :: ty as a type signature for that
       same definition.  The type is rejected precisely when the type
       is ambiguous.
          class Wob a b where
            to :: a -> b
            from :: b -> a
          foo x = [x, to (from x)]
       GHC 7.0 would infer the ambiguous type
          foo :: forall a b. Wob a b => b -> [b]
       but that type would give an error whenever it is called; and
       GHC 7.0 would reject that signature if given by the
       programmer.  The new type checker rejects it up front.
       Similarly, with the advent of type families, ambiguous types are
       easy to write by mistake.  See Trac #1897 and linked tickets for
       many examples.  Eg
          type family F a :: *
          f ::: F a -> Int
          f x = 3
       This is rejected because (F a ~ F b) does not imply a~b.  Previously
       GHC would *infer* the above type for f, but was unable to check it.
       Now even the inferred type is rejected -- correctly.
    The main implemenation mechanism is to generalise the abe_wrap
    field of ABExport (in HsBinds), from [TyVar] to HsWrapper. This
    beautiful generalisation turned out to make everything work nicely
    with minimal programming effort.  All the work was fiddling around
    the edges; the core change was easy!

 compiler/deSugar/DsBinds.lhs        |   62 +++-----
 compiler/deSugar/DsExpr.lhs         |    6 +-
 compiler/hsSyn/HsBinds.lhs          |   28 +++-
 compiler/hsSyn/HsUtils.lhs          |   32 +++--
 compiler/main/DynFlags.hs           |   13 +-
 compiler/rename/RnBinds.lhs         |    6 +-
 compiler/typecheck/TcBinds.lhs      |  282 ++++++++++++++++++++--------------
 compiler/typecheck/TcClassDcl.lhs   |   12 +-
 compiler/typecheck/TcEnv.lhs        |  117 +++++++++------
 compiler/typecheck/TcErrors.lhs     |   32 +++--
 compiler/typecheck/TcHsSyn.lhs      |   14 +-
 compiler/typecheck/TcInstDcls.lhs   |   19 ++-
 compiler/typecheck/TcMType.lhs      |    6 +-
 compiler/typecheck/TcRnDriver.lhs   |   14 +-
 compiler/typecheck/TcRnMonad.lhs    |    2 +-
 compiler/typecheck/TcRnTypes.lhs    |   11 +-
 compiler/typecheck/TcSimplify.lhs   |   57 +++++---
 compiler/typecheck/TcTyClsDecls.lhs |    4 +-
 compiler/typecheck/TcType.lhs       |   28 ++--
 19 files changed, 439 insertions(+), 306 deletions(-)

comment:6 Changed 8 years ago by simonpj

Resolution: fixed
Status: newclosed
Test Case: typecheck/should_compile/T5302

Fixed by (a) above! I think you'll be happy.


Note: See TracTickets for help on using tickets.