
Some thoughts on fixities
-------------------------

** The target of a fixity declaration

  When you declare a fixity it should refer to a particular binding of that
  name, not (as in Haskell) the name in general. The reason for this is: it's a
  good design. A particular name might mean different things at different times,
  and so you should be able to assign it different fixities.

  One option then is to somehow attach the fixity declaration to the binding
  site of the name. An argument against this is that it's very nice to give all
  the fixity information in one place:

    infixl 8  +, -
    infixl 10 *, /

  Instead of attaching it to the different definitions.

** The scope of a fixity declaration

  So the question is then what declaration are we referring to when we say

    infix 5 <>

  A simple answer is: the <> in scope. Consider then the following example:

    suc x + y = suc (x + y)
    infixl 10 +

  What's the fixity of + in the body? It clearly has to be infixl 10, since how
  else would you declare it? This illustrates that fixity declarations follow
  different scoping rules from normal declarations.

  If we accept that the scoping for fixity declarations is weird, would there be
  any problems in allowing the fixity to appear before the definition of the
  name?

    infixl 10 +
    suc x + y = suc (x + y)

  Not really. We just get weird scoping in a different way.

** Local fixity declarations

  The examples, so far has been about fixities of declared names. You could also
  imaging declaring fixities for bound names:

    \(+) -> let infixl 9 + in 1 + 2 + 3

  We'll get back to that shortly.

  Another thing to consider is whether it should be possible to redefine the
  fixity of a function. Let's look at the consequences:

  Yes:

    We should be able to write something like the following

      infixl 10 +
      (+) = ...
      foo = 1 + 2 + 3
	where
	  infixr 8 +

    So far nothing strange. What about this example:
    
      infixl 10 +
      (+) = ...
      foo = let infixr 8 +
		x = 1 + 2 + 3
		(+) = ...
		y = 4 + 5 + 6
	    in x + y

    Following what we've said the fixity of + in x should be infixl 10, but this
    looks really weird, considering that we declare the fixity of + in the line
    above x to be infixr 8. In fact it's not even clear which definition of +
    this fixity declaration refers to.

  No:

    Considering the example above this seems like the best choice. There is a
    problem with declaring the fixity of bound names, though. For declared names
    the restriction is simply that the fixity declaration must appear at the
    same level (same module/abstract/private/mutual/let-block), for bound names
    it's not that simple. For instance, we would expect the example above to be
    correct:

      \(+) -> let infixl 9 + in 1 + 2 + 3

    But then we get into the same problem as if we allow redefinition of
    fixities:

      \(+) -> let infixl 9 +
		  foo = 1 + 2 + 3
		  x + y = ...
		  bar = 4 + 5 + 6
	      in foo + bar

    Which + are we declaring the fixity of? To solve this problem we don't allow
    fixity declarations for bound names.

The same block

  Actually the restriction on where the fixity declaration can appear isn't that
  simple as let on above. As mentioned in the beginning it's nice to group the
  fixity declarations of related functions. If some of these functions are
  abstract, private or mutually recursive you wouldn't be able to do this. The
  solution is to use the scoping rule for the blocks. If a name declared inside
  a block is visible outside the block, then the fixity declaration can appear
  outside the block. This means that you can pull fixity declarations out of
  abstract, private, and mutual blocks, but not out of modules of local
  definitions.

  A natural question is if we are allowed to push fixities inside these blocks:

  (+) = ...
  private infixl 10 +

  There's not really a problem with doing this except that since the declaration
  modifiers (private/abstract/mutual) doesn't affect fixity declarations the
  example above could give you the wrong idea (that the fixity isn't exported
  outside the module). For this reason, the example above is disallowed.

Conclusions

  You can declare the fixity of a declared name (but not a bound name). The
  fixity declaration has to appear on the same level as the declaration. The
  only exception to this rule is that fixity declarations can be lifted out of
  abstract, private and mutual blocks.

  The following would be OK:

    infixl 8  +, -
    abstract (+) = ...
    (-) = ...
  --
    abstract (+) = ...
    (-) = ...
    infixl 8  +, -
  --
    abstract infixl 8 +
	     (+) = ...
    infixl 8 -
    (-) = ...
    
  but the following would not be

    abstract infixl 8 +, -
	     (+) = ...
    (-) = ...
  --
    infixl 8 +
    module Plus where
      (+) = ...

 vim: sts=2 sw=2 tw=80
