| 56 | | ==== An alternative: one-the-fly closure conversion ==== |
| | 57 | A problem becomes apparent when we change the example slightly: |
| | 58 | {{{ |
| | 59 | -- unconverted code |
| | 60 | data T = MkT (Int -> Int) |
| | 61 | foo = MkT ((+) (1::Int)) |
| | 62 | |
| | 63 | -- converted code |
| | 64 | appT :: T -> Int -> Int |
| | 65 | appT (MkT f) x = f x |
| | 66 | |
| | 67 | bar = appT foo |
| | 68 | }}} |
| | 69 | Now, we don't have a converted version of T available. Converting it on the fly might be problematic. If `appT` and `bar` reside in different modules, we convert `T` twice and need to make sure the two versions are compatible. Even worse, the module holding `bar` may only import `T` abstractly and hence can neither derive the converted version of `T` nor can it infer suitable conversion functions. In this case, we have to give up on converting `appT foo` (and maybe all of `bar`). |
| | 70 | |
| | 71 | Alternatively, we might decide that we do not convert the case expression in `appT`'s Core code that scrutinises its first argument. Then, the type of the converted function would be |
| | 72 | {{{ |
| | 73 | appT_CC :: Clo T (Clo Int Int) |
| | 74 | }}} |
| | 75 | i.e., it still uses `T`, not `T_CC`. As callers of `appT_CC` also will '''not''' have a converted version of `T` available, everything still fits together nicely. This appears to be a simpler scheme than on-the-fly type conversions. |
| | 76 | |
| | 77 | The same should work for classes and their dictionaries. If we can use unconverted functions in converted code, we can also select from unconverted dictionaries and use the unconverted methods. |