scope 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. The discussion below is a transcript of my thinking process. This means that it
  2. will contain things that were true (or I thought were true) at the time of
  3. writing, but were later revised. For instance, it might say something like: the
  4. canonical form of @x@ is @x@, and then later say that it is @A.x@.
  5. What should the scope analysis do? One option
  6. would be to compute some of the name space stuff, making
  7. all names fully qualified. How does this work for parameterised
  8. modules? We keep namespace declarations and imports, but throw
  9. away open declarations. We also remove all import directives.
  10. > module A (X : Set) where
  11. >
  12. > f = e
  13. > g = .. f .. -- what is the fully qualified name of f?
  14. @f -> A.f@. In parameterised modules you get a name space with
  15. the name of the module:
  16. > module A (X : Set) where
  17. > namespace A = A X
  18. > module A where
  19. > f = e
  20. > namespace A' = A
  21. > g = e'
  22. > h = A' g -- is this valid? no. A' is a snapshot of A
  23. Example name space maps
  24. > import B, renaming (f to g) -- B : g -> B.f
  25. > namespace B' = B, renaming (g to h) -- B' : h -> B.f
  26. > open B', renaming (h to i) -- local: i -> B.f
  27. With parameterised modules
  28. > import B -- B/1 : f -> _
  29. > namespace B' = B e -- B' : f -> B'.f
  30. The treatment of namespace declarations differ in the two examples.
  31. Solution: namespace declarations create new names so in the first example
  32. @B': h -> B'.h@? We lose the connection to B, but this doesn't matter in scope
  33. checking. We will have to repeat some of the work when type checking, but
  34. probably not that much.
  35. Argh? The current idea was to compute much of the scoping at this point,
  36. simplifying the type checking. It might be the case that we would like to
  37. know what is in scope (for interaction\/plugins) at a particular program
  38. point. Would we be able to do that with this approach? Yes. Question marks
  39. and plugin calls get annotated with ScopeInfo.
  40. Modules aren't first class, so in principle we could allow clashes between
  41. module names and other names. The only place where we mix them is in import
  42. directives. We could use the Haskell solution:
  43. > open Foo, using (module Bar), renaming (module Q to Z)
  44. What about exporting name spaces? I think it could be useful.
  45. Simple solution: replace the namespace keyword with 'module':
  46. > module Foo = Bar X, renaming (f to g)
  47. Parameterised?
  48. > module Foo (X : Set) = Bar X, renaming (f to g)?
  49. Why not?
  50. This way there the name space concept disappear. There are only modules.
  51. This would be a Good Thing.
  52. Above it says that you can refer to the current module. What happens in this
  53. example:
  54. > module A where
  55. > module A where
  56. > module A where x = e
  57. > A.x -- which A? Current, parent or child?
  58. Solution: don't allow references to the current or parent modules. A
  59. similar problem crops up when a sibling module clashes with a child module:
  60. > module Foo where
  61. > module A where x = e
  62. > module B where
  63. > module A where x = e'
  64. > A.x
  65. In this case it is clear, however, that the child module shadows the
  66. sibling. It would be nice if we could refer to the sibling module in some
  67. way though. We can:
  68. > module Foo where
  69. > module A where x = e
  70. > module B where
  71. > private module A' = A
  72. > module A where x = e'
  73. > A'.x
  74. Conclusion: disallow referring to the current modules (modules are non-recursive).
  75. What does the 'ScopeInfo' really contain? When you 'resolve' a name you should
  76. get back the canonical version of that name. For instance:
  77. > module A where
  78. > x = e
  79. > module B where
  80. > y = e'
  81. > -- x -> x, y -> y
  82. > -- B.y -> B.y
  83. > ...
  84. What is the canonical form of a name? We would like to remove as much name juggling
  85. as possible at this point.
  86. Just because the user cannot refer to the current module doesn't mean that we shouldn't
  87. be able to after scope analysis.
  88. > module A where
  89. > x = e
  90. > module B where
  91. > y = e'
  92. > -- * x -> A.x
  93. > -- * y -> A.B.y
  94. > -- * B.y -> A.B.y
  95. > import B as B'
  96. > -- * B'.x -> B.x
  97. > import C
  98. > module CNat = C Nat
  99. > -- * CNat.x -> A.CNat.x
  100. Argh! This whole fully qualified name business doesn't quite cut it for local functions.
  101. We could try some contrived naming scheme numbering clauses and stuff but we probably want
  102. to just use unique identifiers (numbers). It would still be useful to keep the fully
  103. qualified name around, though, so the work is not completely in vain.
  104. How does this influence interfaces and imported modules? Consider:
  105. > module A where x = e
  106. > module B where
  107. > import A
  108. > y = A.x
  109. > module C where
  110. > import A
  111. > y = A.x
  112. > module D where
  113. > import B
  114. > import C
  115. > h : B.y == C.y
  116. > h = refl
  117. It would be reasonable to expect this to work. For this to happen it's important that we
  118. only choose identifiers for the names in A once. Aside: /There is another issue here. A.x
  119. has to be available during type checking of D (for computations) even though it's not in
  120. scope/. That might actually hold the key to the solution. We need to read
  121. interface files for all modules, not just the ones needed for their scope. In other words
  122. interface files must contain references to imported modules. There's still the question of
  123. when to assign unique identifiers. At the moment, scope checking and import chasing is
  124. intertwined. We would have to keep track of the files we've generated uids for and check
  125. for each import whether we need to generate new names. How about the type signatures and
  126. definitions in the interface files? Maybe it would be easier to come up with a way of naming
  127. local functions and just stick to the fully qualifed names idea...
  128. Or, we could go with qualified unique identifiers. A (qualified) name has two uids: one for
  129. the top-level module (file) and one for the name. That way we can generate uids once and store
  130. them in the interface file and we only have to generate uids for new modules, or maybe just
  131. stick with the module name as the uid for the time being.