fixities 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. Some thoughts on fixities
  2. -------------------------
  3. ** The target of a fixity declaration
  4. When you declare a fixity it should refer to a particular binding of that
  5. name, not (as in Haskell) the name in general. The reason for this is: it's a
  6. good design. A particular name might mean different things at different times,
  7. and so you should be able to assign it different fixities.
  8. One option then is to somehow attach the fixity declaration to the binding
  9. site of the name. An argument against this is that it's very nice to give all
  10. the fixity information in one place:
  11. infixl 8 +, -
  12. infixl 10 *, /
  13. Instead of attaching it to the different definitions.
  14. ** The scope of a fixity declaration
  15. So the question is then what declaration are we referring to when we say
  16. infix 5 <>
  17. A simple answer is: the <> in scope. Consider then the following example:
  18. suc x + y = suc (x + y)
  19. infixl 10 +
  20. What's the fixity of + in the body? It clearly has to be infixl 10, since how
  21. else would you declare it? This illustrates that fixity declarations follow
  22. different scoping rules from normal declarations.
  23. If we accept that the scoping for fixity declarations is weird, would there be
  24. any problems in allowing the fixity to appear before the definition of the
  25. name?
  26. infixl 10 +
  27. suc x + y = suc (x + y)
  28. Not really. We just get weird scoping in a different way.
  29. ** Local fixity declarations
  30. The examples, so far has been about fixities of declared names. You could also
  31. imaging declaring fixities for bound names:
  32. \(+) -> let infixl 9 + in 1 + 2 + 3
  33. We'll get back to that shortly.
  34. Another thing to consider is whether it should be possible to redefine the
  35. fixity of a function. Let's look at the consequences:
  36. Yes:
  37. We should be able to write something like the following
  38. infixl 10 +
  39. (+) = ...
  40. foo = 1 + 2 + 3
  41. where
  42. infixr 8 +
  43. So far nothing strange. What about this example:
  44. infixl 10 +
  45. (+) = ...
  46. foo = let infixr 8 +
  47. x = 1 + 2 + 3
  48. (+) = ...
  49. y = 4 + 5 + 6
  50. in x + y
  51. Following what we've said the fixity of + in x should be infixl 10, but this
  52. looks really weird, considering that we declare the fixity of + in the line
  53. above x to be infixr 8. In fact it's not even clear which definition of +
  54. this fixity declaration refers to.
  55. No:
  56. Considering the example above this seems like the best choice. There is a
  57. problem with declaring the fixity of bound names, though. For declared names
  58. the restriction is simply that the fixity declaration must appear at the
  59. same level (same module/abstract/private/mutual/let-block), for bound names
  60. it's not that simple. For instance, we would expect the example above to be
  61. correct:
  62. \(+) -> let infixl 9 + in 1 + 2 + 3
  63. But then we get into the same problem as if we allow redefinition of
  64. fixities:
  65. \(+) -> let infixl 9 +
  66. foo = 1 + 2 + 3
  67. x + y = ...
  68. bar = 4 + 5 + 6
  69. in foo + bar
  70. Which + are we declaring the fixity of? To solve this problem we don't allow
  71. fixity declarations for bound names.
  72. The same block
  73. Actually the restriction on where the fixity declaration can appear isn't that
  74. simple as let on above. As mentioned in the beginning it's nice to group the
  75. fixity declarations of related functions. If some of these functions are
  76. abstract, private or mutually recursive you wouldn't be able to do this. The
  77. solution is to use the scoping rule for the blocks. If a name declared inside
  78. a block is visible outside the block, then the fixity declaration can appear
  79. outside the block. This means that you can pull fixity declarations out of
  80. abstract, private, and mutual blocks, but not out of modules of local
  81. definitions.
  82. A natural question is if we are allowed to push fixities inside these blocks:
  83. (+) = ...
  84. private infixl 10 +
  85. There's not really a problem with doing this except that since the declaration
  86. modifiers (private/abstract/mutual) doesn't affect fixity declarations the
  87. example above could give you the wrong idea (that the fixity isn't exported
  88. outside the module). For this reason, the example above is disallowed.
  89. Conclusions
  90. You can declare the fixity of a declared name (but not a bound name). The
  91. fixity declaration has to appear on the same level as the declaration. The
  92. only exception to this rule is that fixity declarations can be lifted out of
  93. abstract, private and mutual blocks.
  94. The following would be OK:
  95. infixl 8 +, -
  96. abstract (+) = ...
  97. (-) = ...
  98. --
  99. abstract (+) = ...
  100. (-) = ...
  101. infixl 8 +, -
  102. --
  103. abstract infixl 8 +
  104. (+) = ...
  105. infixl 8 -
  106. (-) = ...
  107. but the following would not be
  108. abstract infixl 8 +, -
  109. (+) = ...
  110. (-) = ...
  111. --
  112. infixl 8 +
  113. module Plus where
  114. (+) = ...
  115. vim: sts=2 sw=2 tw=80