[GHC] #10928: Refine pattern synonym signatures
GHC
ghc-devs at haskell.org
Mon Oct 5 13:09:04 UTC 2015
#10928: Refine pattern synonym signatures
-------------------------------------+-------------------------------------
Reporter: mpickering | Owner:
Type: bug | Status: new
Priority: normal | Milestone: 8.0.1
Component: Compiler | Version: 7.10.2
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: Other | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
-------------------------------------+-------------------------------------
Comment (by goldfire):
While we're tackling this problem, I'd like to repeat my arguments (made
last round during the debate about this syntax) that we've gotten the
order of the constraints wrong. Not less natural, but wrong.
Consider this:
{{{
data T a where
MkT :: (Show a, Show b) => a -> b -> T a
pattern P :: (Show a, Show b) => (Eq a, Num a) => b -> T a
pattern P x = MkT 3 x
foo :: T Int -> Bool
foo (P _) = False
}}}
This code typechecks. But let's delve into that pattern type signature a
bit. It has 4 parts:
1. The provided constraints: `(Show a, Show b)`
2. The required constraints: `(Eq a, Num a)`
3. The arguments: `b`
4. The result: `T a`
Let's look, in particular, at the type variables here. Somewhat by
definition, only the universal variables are mentioned in the result. Thus
`a` is universal. Any other type variables are existential. Thus `b` is
existential. Here is what is in scope in the 4 regions:
1. Provided: universals and existentials are in scope
2. Required: only universals are in scope
3. Arguments: universals and existentials are in scope
4. Result: only universals are in scope
Look how the scoping rules flip-flop!
Wait. What I've written is a lie. In GHC 7.10, the existentials ''are'' in
scope in the required constraints. But this is hogwash. There's nothing at
all useful that can be done by having a required constraint on an
existential. Required constraints must be established before the pattern
is matched. But existentials are available only after the match. Indeed,
putting a `Read b` constraint in the required set makes `foo` fail to
type-check. `b` should simply not be in scope for the required
constraints.
By reversing the order of provided/required, our scopes would nest.
I would also support the following, verbose but clear syntax:
{{{
pattern P :: { universals = [a]
, existentials = [b]
, provided = (Show a, Show b)
, required = (Eq a, Num a)
, arguments = [b]
, result = T a }
}}}
The `provided`, `required`, etc, above are keywords, essentially, but they
wouldn't clobber any existing syntax. We know precisely when we're parsing
a pattern type signature. The only compulsory entry in there would be
`result`. The `universals` and `existentials` are lists of type variable
''binders'', where we could assign kinds to the variables. These would be
inferred, as usual, if they are omitted.
(You might think we don't need to have binders anywhere, because we can
always use a kind annotation on a usage of a variable to fix its kind. But
this won't work in 8.0 for two reasons. 1) With visible type application,
it would be nice to give an ordering to the variables, with universals
always before existentials, and 2) when we have kind families, putting a
kind family in a use site could be ambiguous, whereas it is unambiguous at
a binding site.)
This version has the considerable advantage of being easier to read and
search for. It also means we could deprecate the current syntax for a
cycle -- nothing would ''change'' in meaning.
To be clear, I'm not 100% convinced that what I've suggested is an
improvement, as it's quite verbose. But I'm reminded of one argument that
came up during the role annotations debate that code is read much, much
more often than it is written. Optimize for reading over writing!
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/10928#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list