wiki:QualifiedOperators

Version 6 (modified by simonmar@…, 5 years ago) (diff)

--

Proposal: QualifiedOperators


Ticket #127
Dependencies
Related replaces QualifiedIdentifiers and CompositionAsDot

Compiler support

GHC full (-XNewQualifiedOperators)
nhc98 none
Hugs none
UHC none
JHC none
LHC none

Summary

Change the syntax for qualified operators from Prelude.>>= to Prelude.(>>=).

Description

The problem is that right now, qualified operators are written like

   Prelude.>>=

but the difficulty with this is that we now have lexemes like Prelude.. (qualified '.'), which means for example that

  [Red..]

doesn't parse as you might expect: Red.. is a qualified operator.

The proposal is as follows. Qualified operators are written

  Prelude.(>>=)

and are prefix; that is, the above is a qualified version of (>>=). One obvious advantage is that this is much easier to read: the dot is clearly separated from the operator being qualified.

Prelude.(>>=) has to be a single lexeme, because there's no way to lift the syntax of qualified names into the context-free grammar. So this forces us to move the syntax for parenthesized operators and `..` down to the lexical syntax (back where it was in Haskell 1.2?). But that's not too bad; one possibility for the lexical grammar is

  var     -> varid  |  ( varsym )
  qvar    -> [ modid . ] var

  varop   -> varsym  |  `var`
  qvarop  -> varsym  |  `qvar`

(with identical rules for constructors). This grammar has slightly fewer productions than Haskell 98.

Note that this grammar is nested differently than in Haskell 98: the layering is

  • varid: plain variables
  • var: adds parenthesised operators
  • qvar: adds qualification
  • qvarop: adds ..

So, an infix qualified operator is written

  `Prelude.(>>=)`

for consistency we also allow `(>>=)`. The fixity of these would be the same as the fixity of >>=.

You might argue that it is inconsistent to allow `(+)` but not allow (`plus`), but the justification is simply that (..) and `..` are not dual in this design.

This proposal simplifies the story for composition: we don't have to worry about whether you need a space after Prelude... Also, Prelude.(.) is much easier to read. The only disadvantage I can see is that it could break some code, but probably very little.

Summary: pros

  • Eliminates odd cases in the lexical syntax: M.., M..., M.... are 1, 2, and 3 lexemes respectively in Haskell 98 (see also QualifiedIdentifiers). This can be confusing, e.g. [Monday..].
  • A simple rule: if a lexeme begins with a letter, it is not an infix operator. Infix operators begin with a symbol character or `.

Summary: cons

  • The syntax for infix qualified operators is heavier: `Prelude.(>>=)` vs. Prelude.>>=
  • Using the workaround let (>>=) = Prelude.(>>=) in ... does not work, because >>= has the default fixity.
  • `...` and (...) are not dual
  • we lose some consistency with sections, which become quite unwieldy with the new syntax:
             left section  right section   prefix
unqualified  (+ 1)         (1 +)           (+)
Haskell 98   (M.+ 1)       (1 M.+)         (M.+)
proposed     (`M.(+)` 1)   (1 `M.(+)`)     M.(+)
   or(*)     (M.(+) 1)     (flip M.(+) 1)

(*) only if precedence isn't important, e.g. not in cases like `M.(+)` x `M.(*)` y.

References

Report Delta