Difference between revisions of "GHC/Type system"
From HaskellWiki
< GHC
(→Overlapping instances) |
(fix link to OverlappingInstances) |
||
(12 intermediate revisions by 7 users not shown) | |||
Line 2: | Line 2: | ||
<span style='font-size: x-large; font-weight: bold'>Type system extensions in GHC</span> |
<span style='font-size: x-large; font-weight: bold'>Type system extensions in GHC</span> |
||
− | GHC comes with a rather large collection of type-system extensions (beyond Haskell 98). |
+ | GHC comes with a rather large collection of type-system extensions (beyond Haskell 98). {{GHCUsersGuide|exts||a section on Language Extensions}} But this page is a place to record user-oriented observations, notes, and suggestions on how to use them. |
⚫ | |||
+ | * '''[[GHC/Indexed_types|Indexed data types]]''' |
||
− | |||
+ | * '''[[GHC/TypeHoles|Agda-like "holes" in GHC]]''' |
||
− | It's quite common for people to write a function definition without a type signature, load it into GHCi, use <tt>:t</tt> 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: |
||
⚫ | |||
− | <haskell> |
||
⚫ | |||
− | class C a b where |
||
⚫ | * '''Overlapping instances'''. GHC supports overlapping instances, with carefully specified rules. Make sure you read the [http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/instances.html#overlapping-instances relevant sections of the user manual]. Here is an application note about [[GHC/AdvancedOverlap|advanced use of overlapping instances]], combined with functional dependencies. |
||
− | foo :: a -> b |
||
+ | * '''[[GHC/SuperClass|Super-Class Constraints: Type Families, Type Equalities, FunDep, Overlaps]]''' |
||
− | |||
+ | * '''[[GHC/Coercible|Safe coercions using Coercible]]''' |
||
− | konst :: a -> Bool |
||
− | konst x = True |
||
− | |||
− | f :: (C a b) => a -> Bool |
||
− | f x = konst (foo x) |
||
− | </haskell> |
||
− | If you compile this code, you'll get this error: |
||
− | <pre> |
||
− | 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) |
||
− | </pre> |
||
− | What's going on? GHC knows, from the type signature that <tt>x::a</tt>. Then applying <tt>foo</tt> means GHC must pick a return type for <tt>foo</tt>, say <tt>b1</tt>, and generates the type constraint <tt>(C a b1)</tt>. The function <tt>konst</tt> just discards its argument, ''so nothing further is known abouut <tt>b1</tt>''. |
||
− | |||
− | Now GHC finished typechecking the right hand side of <tt>f</tt>, so next it checks that the constraints ''needed'' in the RHS, namely <tt>(C a b1)</tt>, can be satisfied from the constraints ''provided'' by the type signature, namely <tt>(C a b)</tt>. Alas there is nothing to tell GHC that <tt>b</tt> and <tt>b1</tt> should be identified together; hence the complaint. (Probably you meant to put a functional dependency in the class declaration, thus |
||
− | <haskell> |
||
− | class C a b | a->b where ... |
||
− | </haskell> |
||
− | but you didn't.) |
||
− | |||
− | The surprise is that if you comment out the type signature for <tt>f</tt>, the module will load fine into GHCi! Furthermore <tt>:t</tt> will report a type for <tt>f</tt> that is exactly the same as the type signature that was rejected! |
||
− | |||
− | 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>. If the instances of <tt>C</tt> constrain both type parameters, you'd be in trouble: |
||
− | <haskell> |
||
− | instance C Char Bool where ... |
||
− | </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. |
||
− | |||
− | (However, notice that the call <tt>(f 'a')</tt> would be OK if there was an instance like: |
||
− | <haskell> |
||
− | instance C Char w where ... |
||
− | </haskell> |
||
− | Now the constraint <tt>(C Char b)</tt> matches the instance declaration, even though we know nothing about <tt>b</tt>.) |
||
− | |||
− | 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 == |
||
− | |||
⚫ | |||
− | |||
− | Here is an appliation note about [[GHC/AdvancedOverlap|advanced use of overlapping instances]], combined with functional dependencies. |
||
− | |||
− | == Indexed data types and indexed newtypes == |
||
− | |||
− | [[GHC/Indexed_types|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 [http://hackage.haskell.org/trac/ghc/wiki/Building/GettingTheSources its source repository]. |
||
− | |||
− | == Stand-alone deriving clauses == |
||
− | |||
⚫ | |||
− | ----------------------- |
Latest revision as of 20:32, 23 July 2021
Type system extensions in GHC
GHC comes with a rather large collection of type-system extensions (beyond Haskell 98). The GHC Users Guide has a section on Language Extensions. But this page is a place to record user-oriented observations, notes, and suggestions on how to use them.
- Indexed data types
- Agda-like "holes" in GHC
- "Stand-alone deriving" declarations
- Type signatures and ambiguity
- Overlapping instances. GHC supports overlapping instances, with carefully specified rules. Make sure you read the relevant sections of the user manual. Here is an application note about advanced use of overlapping instances, combined with functional dependencies.
- Super-Class Constraints: Type Families, Type Equalities, FunDep, Overlaps
- Safe coercions using Coercible