| | 1 | Proposal for A: |
| | 2 | |
| | 3 | Allow nested modules. A nested module can occur in any |
| | 4 | position that a data declaration can occur. The syntax of |
| | 5 | a nested module is the same as the syntax of a conventional |
| | 6 | module. |
| | 7 | |
| | 8 | A nested module must have the same hierarchical name as |
| | 9 | the module in which it is nested, followed by a single additional |
| | 10 | component. A name with a single component can be specified |
| | 11 | in the declaration of a nested module; this is syntactic sugar for |
| | 12 | the fully qualified name of the enclosing module followed by that |
| | 13 | single additional component. |
| | 14 | |
| | 15 | When a module M.A is directly nested in module M, there is |
| | 16 | an implied import in the enclosing module M as follows: |
| | 17 | |
| | 18 | import qualified M.A as A |
| | 19 | |
| | 20 | and an implied import in the nested module M.A as follows: |
| | 21 | |
| | 22 | import M |
| | 23 | |
| | 24 | These implied imports may optionally be specified explicitly |
| | 25 | with no effect, or overridden with other explicit imports, |
| | 26 | similarly to the usual implied import of Prelude. |
| | 27 | |
| | 28 | When modules are nested to a depth greater than one, |
| | 29 | similar implied imports exist for all recursively enclosing |
| | 30 | and enclosed modules, with the same rules about |
| | 31 | overriding. |
| | 32 | |
| | 33 | If an enclosing module M has an export list, a nested |
| | 34 | module N at any depth recursively cannot be imported |
| | 35 | by modules not nested inside M unless N is included in |
| | 36 | the export list of M. If M does not have an export list, |
| | 37 | N can be imported by any other module as usual. |
| | 38 | |
| | 39 | In every other respect, a nested module declaration has |
| | 40 | exactly the same effect as any other module declaration. |
| | 41 | In particular, the behavior of nested modules in the |
| | 42 | presence of all corner cases such as data families, etc., |
| | 43 | is specified by this rule. |
| | 44 | |
| | 45 | The effect of a nested module on the behavior of |
| | 46 | ghc --make is left unspecified as of now, until |
| | 47 | there is feedback from the GHC team. This would |
| | 48 | probably involve GHC looking for A.B and then |
| | 49 | A in turn when it fails to find A.B.C. Or perhaps |
| | 50 | even when A.B.C is found, to identify erroneous |
| | 51 | duplication. Or GHC could stay pretty much as |
| | 52 | it is now, relying on the user to ensure that GHC |
| | 53 | finds the nested module; that would certainly |
| | 54 | be fine for an initial implementation. |
| | 55 | |
| | 56 | |
| | 57 | Usage example: |
| | 58 | |
| | 59 | module Library where |
| | 60 | import Data.Text (Text) |
| | 61 | ... |
| | 62 | type ISBN = Text |
| | 63 | module Book where |
| | 64 | import Data.Text (Text) |
| | 65 | data T = New { name :: Text, iSBN :: ISBN } |
| | 66 | module Checkout where |
| | 67 | import Data.Time |
| | 68 | import qualified Library.Book as Book |
| | 69 | import qualified Library.Borrower as Borrower |
| | 70 | data T = New |
| | 71 | { book :: Book.T, borrower :: Borrower.T, dueDate :: Day } |
| | 72 | module Borrower where |
| | 73 | import Data.Text (Text) |
| | 74 | data T = New { name :: Text, address :: Text } |
| | 75 | module History where |
| | 76 | import qualified Library.Borrower as Borrower |
| | 77 | import qualified Library.Checkout as Checkout |
| | 78 | data T = New { borrower :: Borrower.T, checkouts :: [Checkout.T] } |
| | 79 | |
| | 80 | This makes available in the module Library the |
| | 81 | record types: |
| | 82 | |
| | 83 | Book.T, Checkout.T, Borrower.T, History.T |
| | 84 | |
| | 85 | with constructors: |
| | 86 | |
| | 87 | Book.New, Checkout.New, Borrower.New, History.New |
| | 88 | |
| | 89 | and record accessors: |
| | 90 | |
| | 91 | Book.name, Book.iSBN, |
| | 92 | Checkout.book, Checkout.borrower, Checkout.dueDate, |
| | 93 | Borrower.name, Borrower.address, |
| | 94 | History.borrower, History.checkouts |
| | 95 | |
| | 96 | I believe this specification should be very simple to |
| | 97 | implement and describe. There are some obvious |
| | 98 | shortcomings. But it does provide basic namespacing |
| | 99 | of records with almost no change to Haskell and GHC. |
| | 100 | |
| | 101 | Note also that you need to be careful to avoid mutually |
| | 102 | recursive imports. That is really more of a limitation |
| | 103 | of GHC than a limitation of the specification itself. |
| | 104 | Other compilers might not require that. |
| | 105 | |
| | 106 | I'd be happy to hear ideas about how to develop this |
| | 107 | simple idea further and eliminate some of the |
| | 108 | shortcomings, on condition that it doesn't lead to |
| | 109 | further bikeshedding and significant delay. |
| | 110 | |
| | 111 | One obvious enhancement would be for the |
| | 112 | implied import of the enclosing module to |
| | 113 | include also all names imported into |
| | 114 | the enclosing module, unlike the usual |
| | 115 | convention for imports. I'm not sure if |
| | 116 | there are complications to that though. |
| | 117 | |
| | 118 | ==================== |
| | 119 | |
| | 120 | Whenever any module E imports M unqualified without an |
| | 121 | import list, as in: |
| | 122 | |
| | 123 | import M |
| | 124 | |
| | 125 | then the following implied imports would be added to E: |
| | 126 | |
| | 127 | import qualified M.T as T |
| | 128 | import qualified M.S as S |
| | 129 | |
| | 130 | and whenever E imports M qualified without an |
| | 131 | import list, as in: |
| | 132 | |
| | 133 | import qualified M as Q |
| | 134 | |
| | 135 | then the following implied imports would be |
| | 136 | added to E: |
| | 137 | |
| | 138 | import qualified M.T as Q.T |
| | 139 | import qualified M.S as Q.S |
| | 140 | |
| | 141 | Similarly, if M also contains more deeply nested |
| | 142 | modules and E imports M either qualified or |
| | 143 | unqualified without an import list, the corresponding |
| | 144 | implied imports of the deeply nested modules would |
| | 145 | also be added to E. But in fact, this is nothing |
| | 146 | more than a recursive application of the previous |
| | 147 | rule. |
| | 148 | |
| | 149 | Note that an import statement with an import list |
| | 150 | will never generate any automatic import of |
| | 151 | a nested module. |
| | 152 | |