Tightening up on inferred type signatures

Friends GHC generally obeys this rule * If GHC infers a type f::type, then it's OK for you to add a type signature saying exactly that. For example, it rejects inferred types that are ambiguous. I think this is a good property; it was certainly the source of many bug reports before inferred ambiguous types were rejected. However, up to now (including in 7.8) GHC hasn't followed this rule consistently. In particular, it will infer types like fold :: (Functor (PF a), Regular a) => (PF a b -> b) -> a -> b (where PF is a type family). If you write this as a type signature, GHC will insist on FlexibleContexts and TypeFamilies. So in https://ghc.haskell.org/trac/ghc/ticket/8883, Jan has made GHC check inferred types in the same way that it checks declared types, thus rejecting the above inferred type unless you give the language extensions. This makes the compiler more consistent. But it does mean that some code may be rejected that 7.8 accepts. This email is just a heads-up that you might want to compile your library with 7.10 (i.e. a snapshot of HEAD) well in advance. There will be other breaking changes of course; e.g Applicative will finally be a superclass of Monad, for example. Simon

No objections here.
The types involved really *do* have FlexibleContexts in them, so it makes
sense to require the extension.
The upgrade path for library authors is also clear. It'll complain to add
the extension, and they'll fix it by adding the line of code suggested and
perhaps realize something about their code in the process.
-Edward
On Mon, Apr 21, 2014 at 4:30 AM, Simon Peyton Jones
Friends
GHC generally obeys this rule
· If GHC infers a type *f::type*, then it’s OK for you to add a type signature saying exactly that.
For example, it rejects inferred types that are ambiguous. I think this is a good property; it was certainly the source of many bug reports before inferred ambiguous types were rejected.
However, up to now (including in 7.8) GHC hasn’t followed this rule consistently. In particular, it will infer types like
fold :: (Functor (PF a), Regular a) => (PF a b -> b) -> a -> b
(where PF is a type family). If you write this as a type signature, GHC will insist on FlexibleContexts and TypeFamilies.
So in https://ghc.haskell.org/trac/ghc/ticket/8883, Jan has made GHC check inferred types in the same way that it checks declared types, thus rejecting the above inferred type unless you give the language extensions.
This makes the compiler more consistent.
But it does mean that some code may be rejected that 7.8 accepts. This email is just a heads-up that you might want to compile your library with 7.10 (i.e. a snapshot of HEAD) well in advance. There will be other breaking changes of course; e.g Applicative will finally be a superclass of Monad, for example.
Simon
-- You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libraries+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

] GHC generally obeys this rule ] ] · If GHC infers a type f::type, then it’s OK for you to add a type ] signature saying exactly that. That rule suggests that -XScopedTypeVariables should be on by default, and that you shouldn't need a forall to bring the type variables into scope. I imagine that would lead to harder-to-fix breakage than #8883, but on the other hand type signatures in let/where are pretty rare. Regards, Adam

Simon Peyton Jones
GHC generally obeys this rule
* If GHC infers a type f::type, then it's OK for you to add a type signature saying exactly that.
Independent of language extensions, what about types and classes whose names are not in scope. Is there an implicit "... if you import all the relevant symbols" and the end of the rule? David

| Independent of language extensions, what about types and classes whose
| names are not in scope. Is there an implicit "... if you import all
| the relevant symbols" and the end of the rule?
Good point. I'm honestly unsure how far to push this one! (It'd be relatively easy to check whether they were in scope and complain if not, but ...)
Simon
| -----Original Message-----
| From: haskell-core-libraries@googlegroups.com [mailto:haskell-core-
| libraries@googlegroups.com] On Behalf Of David Mazieres
| Sent: 22 April 2014 00:41
| To: Simon Peyton Jones; Haskell Libraries (libraries@haskell.org);
| core-libraries-committee@haskell.org; GHC users
| Subject: [core libraries] Re: Tightening up on inferred type signatures
|
| Simon Peyton Jones

You can wind up in perfectly legitimate situations where the name for the
type you are working with isn't in scope, but where you can write a
combinator that would infer to have that type. I'd hate to lose that.
It is admittedly of marginal utility at first glance, but there are some
tricks that actually need it, and it can also arise if a type synonym
expands to a type that isn't exported or brought into scope, so trying to
push this line of reasoning too far I is possibly not too productive.
Parts of lens, constraints and probably a few other packages I maintain
would break as hard data points.
-Edward
On Tue, Apr 22, 2014 at 2:44 AM, Simon Peyton Jones
| Independent of language extensions, what about types and classes whose | names are not in scope. Is there an implicit "... if you import all | the relevant symbols" and the end of the rule?
Good point. I'm honestly unsure how far to push this one! (It'd be relatively easy to check whether they were in scope and complain if not, but ...)
Simon
| -----Original Message----- | From: haskell-core-libraries@googlegroups.com [mailto:haskell-core- | libraries@googlegroups.com] On Behalf Of David Mazieres | Sent: 22 April 2014 00:41 | To: Simon Peyton Jones; Haskell Libraries (libraries@haskell.org); | core-libraries-committee@haskell.org; GHC users | Subject: [core libraries] Re: Tightening up on inferred type signatures | | Simon Peyton Jones
writes: | | > GHC generally obeys this rule | > | > * If GHC infers a type f::type, then it's OK for you to add a type | > signature saying exactly that. | | Independent of language extensions, what about types and classes whose | names are not in scope. Is there an implicit "... if you import all | the relevant symbols" and the end of the rule? | | David | | -- | You received this message because you are subscribed to the Google | Groups "haskell-core-libraries" group. | To unsubscribe from this group and stop receiving emails from it, send | an email to haskell-core-libraries+unsubscribe@googlegroups.com. | For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libraries+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

Edward Kmett
You can wind up in perfectly legitimate situations where the name for the type you are working with isn't in scope, but where you can write a combinator that would infer to have that type. I'd hate to lose that.
It is admittedly of marginal utility at first glance, but there are some tricks that actually need it, and it can also arise if a type synonym expands to a type that isn't exported or brought into scope, so trying to push this line of reasoning too far I is possibly not too productive.
Good point. In particular, it's not weird at all want to export type synonyms on their own, particularly where ghost type parameters are used to select between only a few cases. Consider something like this (inspired by postgresql-orm): -- -- These are exported only by an internal module -- data NormalRef = NormalRef data UniqueRef = UniqueRef newtype GeneralizedRef refType targetType = DBRef Int64 -- -- These are exported by the module everyone imports -- type Ref = GeneralizedRef NormalRef type RefUnique = GeneralizedRef UniqueRef mkDBRef :: targetType -> Int64 -> GeneralizedRef refType targetType mkDBRef = const DBRef And now imagine somewhere in your code wanting to do something like the following. mkModelRef = mkDBRef (undefined :: MyModel) In fact, there may even be cases where the type is expressible with synonyms but GHC is unlikely to figure it out. (Or where multiple synonyms are possible and it isn't clear which would be best, so :t still prints the base type.) In short, I'd be sad to see the strict version of this rule put into place, particularly if it makes GHC stricter than Haskell2010 for code that doesn't rely on language extensions. David

On 23/04/2014 20:04, dm-list-haskell-libraries@scs.stanford.edu wrote:
Edward Kmett
writes: You can wind up in perfectly legitimate situations where the name for the type you are working with isn't in scope, but where you can write a combinator that would infer to have that type. I'd hate to lose that.
It is admittedly of marginal utility at first glance, but there are some tricks that actually need it, and it can also arise if a type synonym expands to a type that isn't exported or brought into scope, so trying to push this line of reasoning too far I is possibly not too productive.
Good point. In particular, it's not weird at all want to export type synonyms on their own, particularly where ghost type parameters are used to select between only a few cases. Consider something like this (inspired by postgresql-orm):
Is there an abstraction being protected by only exporting the type synonym in cases like this? Cheers, Ganesh

Not sure.
An even simpler case is something like exporting a Traversal but not
exporting Data.Traversable, which appears in the expansion, etc.
These sorts of things happen in code using lens. Older versions of lens
didn't export all of the types needed to write out the type signature long
hand without extra imports, just to avoid cluttering the namespace.
-Edward
On Wed, Apr 30, 2014 at 2:10 AM, Ganesh Sittampalam
Edward Kmett
writes: You can wind up in perfectly legitimate situations where the name for
On 23/04/2014 20:04, dm-list-haskell-libraries@scs.stanford.edu wrote: the
type you are working with isn't in scope, but where you can write a combinator that would infer to have that type. I'd hate to lose that.
It is admittedly of marginal utility at first glance, but there are some tricks that actually need it, and it can also arise if a type synonym expands to a type that isn't exported or brought into scope, so trying to push this line of reasoning too far I is possibly not too productive.
Good point. In particular, it's not weird at all want to export type synonyms on their own, particularly where ghost type parameters are used to select between only a few cases. Consider something like this (inspired by postgresql-orm):
Is there an abstraction being protected by only exporting the type synonym in cases like this?
Cheers,
Ganesh

Er.. my mistake. Control.Applicative.
That is what it is we don't re-export that is used in Traversal. =)
On Wed, Apr 30, 2014 at 2:47 AM, Edward Kmett
Not sure.
An even simpler case is something like exporting a Traversal but not exporting Data.Traversable, which appears in the expansion, etc.
These sorts of things happen in code using lens. Older versions of lens didn't export all of the types needed to write out the type signature long hand without extra imports, just to avoid cluttering the namespace.
-Edward
On Wed, Apr 30, 2014 at 2:10 AM, Ganesh Sittampalam
wrote: Edward Kmett
writes: You can wind up in perfectly legitimate situations where the name for
On 23/04/2014 20:04, dm-list-haskell-libraries@scs.stanford.edu wrote: the
type you are working with isn't in scope, but where you can write a combinator that would infer to have that type. I'd hate to lose that.
It is admittedly of marginal utility at first glance, but there are some tricks that actually need it, and it can also arise if a type synonym expands to a type that isn't exported or brought into scope, so trying to push this line of reasoning too far I is possibly not too productive.
Good point. In particular, it's not weird at all want to export type synonyms on their own, particularly where ghost type parameters are used to select between only a few cases. Consider something like this (inspired by postgresql-orm):
Is there an abstraction being protected by only exporting the type synonym in cases like this?
Cheers,
Ganesh
participants (6)
-
adam vogt
-
David Mazieres
-
dm-list-haskell-libraries@scs.stanford.edu
-
Edward Kmett
-
Ganesh Sittampalam
-
Simon Peyton Jones