Version 5 (modified by simonpj@…, 9 years ago) (diff)

--

## Make pattern bindings monomorphic

### The Proposal

I propose that we make all pattern bindings completely monomorphic (regardless of type signatures). As a result, the expression

```  let (p,q) = (\x -> x, True) in (p True, p 'c')
```

would fail to typecheck, because it requires p to be polymorphic. The program would be rejected even if p had a type signature:

```  let { p :: a -> a
; (p,q) = (\x -> x, True)
} in (p True, p 'c')
```

We need to be precise about what a "pattern binding" is. Definition: a pattern binding has the form pat=rhs, where pat is not simply a variable. Examples:

```  (x,y) = e    -- Pattern binding
[x]   = e    -- Pattern binding
(x)   = e    -- Pattern binding
x@y   = e    -- Pattern binding
~x    = e    -- Pattern binding

x     = e    -- NOT a pattern binding
```

This rule is simple and easy to remember.

Notice that enclosing the variable in parens, thus (x)=e, makes it a pattern binding, and therfore forces it to be monomorphic. So this is a way to get the monomorphic form of binding that John Hughes has, at times, argued for.

Another way to say it is this: only function bindings are generalised, where a function binding has the form

f p1 ... pn = e

where n>=0. The n=0 case is a bare variable.

### Discussion

At the moment you can say

```	let (f,g) = e in ...
```

and get *polymorphic* values f,g. This causes a good deal of trouble in the implementation (think of what the System F translation looks like), and it's an odd thing to do. Why odd? Well here it's fine:

```	data T = C (forall a. a->a)
h x = let C f = e in ...
```

Constructor C has a polymorphic argument, so we can match e against (C f) and get a polymorphic function. But in the first example, (,) only takes monomorphic arguments, so we have to generalise after selection. To put it another way, even if the "..." is definitely strict in f, we cannot transform to

```	case e of (f,g) -> ...
```

## Experiment

In July I changed GHC (the HEAD) to make pattern bindings monomorphic by default. (A binding of a simple variable is not considered to be a pattern binding.) The flag -fno-mono-pat-binds restores the standard behaviour. I deliberately made the new behaviour the default so that I'd hear of any breakage.

The interesting observation is this: all of the libraries compile without a tremor, and I have received only one message remarking on the new behaviour. Ross Paterson sent me this code

```import Control.Monad.ST

newtype ListMap m a b = ListMap ([a] -> m [b])

runMap :: (forall s. ListMap (ST s) a b) -> [a] -> [b]
runMap lf as = runST (f as)
where ListMap f = lf
```

This no longer works because f isn't polymorphic, and runST needs it to be. It's easily fixed:

```runMap lf as = runST (f as)
where f = case lf of { ListMap f -> f }
```

My conclusion: polymorphic pattern bindings is a feature that is virtually never used, and not even necessary then. We should nuke them.