# GHC/Type system

### From HaskellWiki

(→Type signatures and ambiguity) |
(→Type signatures and ambiguity) |
||

Line 39: | Line 39: | ||

Here's what's happening. Without the type signature, GHC picks an arbitrary type for <tt>x</tt>, say <tt>x::a</tt>. Then applying <tt>foo</tt> means GHC must pick a return type for <tt>foo</tt>, say <tt>b</tt>, and generates the type constraint <tt>(C a b)</tt>. The function <tt>konst</tt> just discards its argument, so nothing further is known abouut <tt>b</tt>. Finally, GHC gathers up all the constraints arising from the right hand side, namely <tt>(C a b)</tt>, and puts them into the inferred type of <tt>f</tt>. So GHC ends up saying that <hask>f :: (C a b) => a -> Bool</hask>. | Here's what's happening. Without the type signature, GHC picks an arbitrary type for <tt>x</tt>, say <tt>x::a</tt>. Then applying <tt>foo</tt> means GHC must pick a return type for <tt>foo</tt>, say <tt>b</tt>, and generates the type constraint <tt>(C a b)</tt>. The function <tt>konst</tt> just discards its argument, so nothing further is known abouut <tt>b</tt>. Finally, GHC gathers up all the constraints arising from the right hand side, namely <tt>(C a b)</tt>, and puts them into the inferred type of <tt>f</tt>. So GHC ends up saying that <hask>f :: (C a b) => a -> Bool</hask>. | ||

− | This is probably a very stupid type. Suppose you called <tt>f</tt> thus: <tt>(f 'a')</tt>. Then you'd get a constraint <tt>(C Char b)</tt> where nothing is known about <tt>b</tt>. | + | This is probably a very stupid type. Suppose you called <tt>f</tt> thus: <tt>(f 'a')</tt>. Then you'd get a constraint <tt>(C Char b)</tt> where nothing is known about <tt>b</tt>. If the instances of <tt>C</tt> constrain both type parameters, you'd be in trouble: |

− | < | + | |

− | + | ||

− | </ | + | |

− | + | ||

<haskell> | <haskell> | ||

instance C Char Bool where ... | instance C Char Bool where ... | ||

</haskell> | </haskell> | ||

− | + | The call gives a <tt>(C Char b)</tt> constraint, with absolutely no way to fix <tt>b</tt> to be <tt>Bool</tt>, or indeed anything else. We're back to very much the same situation as before; it's just that the error is deferred until we call <tt>f</tt>, rather than when we define it. | |

− | This behaviour isn't ideal. It really only arises in programs that are ambiguous anyway (that is, they could never really work), but it is undoubtedly confusing. But I don't know | + | However, the call <tt>(f 'a')</tt> would be OK if there was an instance like: |

+ | <haskell> | ||

+ | instance C Char b where ... | ||

+ | </haskell> | ||

+ | This behaviour isn't ideal. It really only arises in programs that are ambiguous anyway (that is, they could never really work), but it is undoubtedly confusing. But I don't know an easy way to improve it. Yet, anyway. | ||

== Overlapping instances == | == Overlapping instances == |

## Revision as of 16:46, 20 February 2007

Type system extensions in GHC

GHC comes with a rather large collection of type-system extensions (beyond Haskell 98). They are all documented in the user manual, but this page is a place to record observations, notes, and suggestions on them.

## Contents |

## 1 Type signatures and ambiguity

It's quite common for people to write a function definition without a type signature, load it into GHCi, use `:t` to see what type it has, and then cut-and-paste that type into the source code as a type signature. Usually this works fine, but alas not always. Perhaps this is a deficiency in GHC, but here's one way it can happen:

class C a b where foo :: a -> b konst :: a -> Bool konst x = True f :: (C a b) => a -> Bool f x = konst (foo x)

If you compile this code, you'll get this error:

Foo1.hs:12:13: Could not deduce (C a b1) from the context (C a b) arising from use of `foo' at Foo1.hs:12:13-17 Possible fix: add (C a b1) to the type signature(s) for `f' In the first argument of `konst', namely `(foo x)' In the expression: konst (foo x) In the definition of `f': f x = konst (foo x)

What's going on? GHC knows, from the type signature that `x::a`. Then applying `foo` means GHC must pick a return type for `foo`, say `b1`, and generates the type constraint `(C a b1)`. The function `konst` just discards its argument, *so nothing further is known abouut b1*.

Now GHC finished typechecking the right hand side of `f`, so next it checks that the constraints *needed* in the RHS, namely `(C a b1)`, can be satisfied from the constraints *provided* by the type signature, namely `(C a b)`. Alas there is nothing to tell GHC that `b` and `b1` should be identified together; hence the complaint. (Probably you meant to put a functional dependency in the class declaration, thus

class C a b | a->b where ...

but you didn't.)

The surprise is that if you comment out the type signature for `f`, the module will load fine into GHCi! Furthermore `:t` will report a type for `f` that is exactly the same as the type signature that was rejected!

`x`, say

`x::a`. Then applying

`foo`means GHC must pick a return type for

`foo`, say

`b`, and generates the type constraint

`(C a b)`. The function

`konst`just discards its argument, so nothing further is known abouut

`b`. Finally, GHC gathers up all the constraints arising from the right hand side, namely

`(C a b)`, and puts them into the inferred type of

`f`. So GHC ends up saying that

This is probably a very stupid type. Suppose you called `f` thus: `(f 'a')`. Then you'd get a constraint `(C Char b)` where nothing is known about `b`. If the instances of `C` constrain both type parameters, you'd be in trouble:

instance C Char Bool where ...

The call gives a `(C Char b)` constraint, with absolutely no way to fix `b` to be `Bool`, or indeed anything else. We're back to very much the same situation as before; it's just that the error is deferred until we call `f`, rather than when we define it.

However, the call `(f 'a')` would be OK if there was an instance like:

instance C Char b where ...

This behaviour isn't ideal. It really only arises in programs that are ambiguous anyway (that is, they could never really work), but it is undoubtedly confusing. But I don't know an easy way to improve it. Yet, anyway.

## 2 Overlapping instances

Here an interesting message about the interaction of existential types and overlapping instances.

## 3 Indexed data types and indexed newtypes

Indexed data types (including associated data types) are a very recent addition to GHC's type system extensions that is not yet included in the user manual. To use the extension, you need to obtain a version of GHC from its source repository.

## 4 Stand-alone deriving clauses

Bjorn Bringert has recently implemented "stand-alone deriving" declarations.