| 7 | | The first thing to realise is that GHC uses a ''single'' data type for types, even though there are two different "views". |
| | 7 | The single data type {{{Type}}} is used to represent |
| | 8 | * Types (possibly of higher kind); e.g. `[Int]`, `Maybe` |
| | 9 | * Coercions; e.g. `trans (sym g) h` |
| | 10 | * Kinds (which classify types and coercions); e.g. `(* -> *)`, `T :=: [Int]` |
| | 11 | * Sorts (which classify types); e.g. `TY`, `CO` |
| | 12 | |
| | 13 | GHC's use of [wiki:Commentary/Compiler/FC coercions and equality constraints] is important enough to deserve its own page. |
| | 14 | |
| | 15 | The module {{{TypeRep}}} exposes the representation becauese a few other modules ({{{Type}}}, {{{TcType}}}, {{{Unify}}}, etc) work directly on its representation. However, you should not lightly pattern-match on {{{Type}}}; it is meant to be an abstract type. Instead, try to use functions defined by {{{Type}}}, {{{TcType}}} etc. |
| | 16 | |
| | 17 | == Views of types == |
| | 18 | |
| | 19 | Even when considering only types (not kinds, sorts, coercions) you need to know that GHC uses a ''single'' data type for types, even though there are two different "views". |
| 23 | | The module {{{TypeRep}}} exposes the representation becauese a few other modules ({{{Type}}}, {{{TcType}}}, {{{Unify}}}, etc) work directly on its representation. However, you should not lightly pattern-match on {{{Type}}}; it is meant to be an abstract type. Instead, try to use functions defined by {{{Type}}}, {{{TcType}}} etc. |
| | 34 | The "view" functions are ''shallow'', not deep---a view function just looks at the ''root'' of the tree representing the type. For example, part of the `coreView` function ([[GhcFile(compiler/types/Type]]) looks like this: |
| | 35 | {{{ |
| | 36 | coreView :: Type -> Maybe Type |
| | 37 | coreView (PredTy p) = Just (predTypeRep p) |
| | 38 | coreView (NoteTy _ ty) = Just ty |
| | 39 | coreView other = Nothing |
| | 40 | }}} |
| | 41 | Notice that in the `NoteTy` case, `coreView` does not call itself. Now, clients of the view look like this: |
| | 42 | {{{ |
| | 43 | splitFunTy_maybe :: Type -> Maybe (Type,Type) |
| | 44 | splitFunTy_maybe ty | Just ty' <- coreView ty = splitFunTy_maybe ty' |
| | 45 | splitFunTy_maybe (FunTy t1 t2) = Just (t1,t2) |
| | 46 | splitFunTy_maybe other = Nothing |
| | 47 | }}} |
| | 48 | Notice the first line, which uses the view, and recurses when the view 'fires'. Since `coreView` is non-recursive, GHC will inline it, and the optimiser will ultimately produce somethign like: |
| | 49 | {{{ |
| | 50 | splitFunTy_maybe :: Type -> Maybe (Type,Type) |
| | 51 | splitFunTy_maybe (PredTy p) = splitFunTy_maybe (predTypeRep p) |
| | 52 | splitFunTy_maybe (NoteTy _ ty) = splitFunTy_maybe ty |
| | 53 | splitFunTy_maybe (FunTy t1 t2) = Just (t1,t2) |
| | 54 | splitFunTy_maybe other = Nothing |
| | 55 | }}} |
| | 56 | Neat, huh? |