[Haskell-cafe] A better syntax for qualified operators?

Brian Hulley brianh at metamilk.com
Wed Sep 27 16:20:20 EDT 2006

Hi -
Consider the scenario when you want to find a function that returns the i'th 
element of an array but all you know is that there is a module called 
Data.Array.IArray that will probably have such a function in it. So you 
start typing in your program:

        ith = Data.Array.IArray.

at this point, you'd hope the editor you're using would somehow display a 
list of avaliable values exported from Data.Array.IArray including the 
indexing function, so you could select it, thus I would *like* to be able to 
use the syntax:

        ith = Data.Array.IArray.(!)

because it's not the user's fault that the person who wrote 
Data.Array.IArray decided to use a symbol instead of an identifier for this 
function - the user of Data.Array.IArray in this case just wants to see 
normal identifiers to use with prefix application so the use of (!) at this 
point effectively gets rid of the unwanted operatorness associated with the 

However the current syntax of Haskell would not allow this. Instead you have 
to write:

        ith = (Data.Array.IArray.!)

The problem is that the user of Data.Array.IArray has to know already in 
advance, before typing the 'D' of "Data", that the indexing function has 
been named with a symbol instead of an identifier, but this knowledge is 
only available later, when the user has typed the '.' after "IArray", so the 
current syntax would be frustrating for the user because the user then has 
to go all the way back and insert an opening paren before the 'D'.

Also, consider the appearance of:

        ith = (Data.Array.IArray.!) arr i
        b = Data.Array.IArray.bounds arr
        ith = Data.Array.IArray.(!) arr i
        b = Data.Array.IArray.bounds arr

I'm not sure if I've managed to explain this problem clearly enough, but my 
proposal is that we might consider changing the lexical syntax of Haskell as 

    varId ::= id
    varOp ::= symbol
    varIdOp ::= ` varId
    varOpId ::= ( varOp )
    varOpIdOp ::= ` varOpId

    qvarId ::= {conId .}+ varId    -- { }+ denotes 1 or more times
    qvarIdOp ::= ` qvarId
    qvarOp ::= {conId .}+ varOp
    qvarOpId ::= {conId .}+ varOpId
    qvarOpIdOp ::= `qvarOpId

In other words, to turn an operator symbol into an id, the parentheses would 
be put immediately around the symbol (with no spaces since this is lexical 
syntax), and to turn an id into an operator the backquote is put in front of 
the entire (qualified) id.

(Also the trailing backquote in the existing syntax is redundant)

The above syntax would have 3 advantages:
    1) It allows the client of a module to write code without having to 
worry if the author of the module used symbols or identifiers to name 
functions - everything exported from the module can be made to appear as if 
it was named by an identifier (ie OpId)
    2) Moving the parentheses to the lexical syntax makes syntax 
highlighting easier (because there are no comments to worry about inside the 
OpId) and also makes parsing simpler because all the mess associated with 
Ops versus Ids is handled by the lexer
    3) It allows an editor to make a distinction between

            (+)        -- an operator turned into an identifier - varOpId
            ( + )      -- an expression with 2 gaps in it which should be 
marked as incomplete
            (+ )       -- a section with 1 gap

Some examples of the proposed syntax are:

        ith = Data.Array.IArray.(!) arr i
        foo = k `Math.(+) 6    -- default precendence
        bar = k Math.+ 6        -- using precedence of + in module Math

When you try to write an editor for Haskell (or some subset of it), you 
quickly discover these areas of Haskell syntax like the above which need to 
be changed to get an optimum interactive editing experience. I think it *is* 
possible to adjust the Haskell grammar so that it is LL(1) and the only 
reason it is not already LL(1) seems to be that the grammar has been 
designed with compilers (which only need to deal with complete modules) in 
mind rather than programmers interactively editing in mind.

(The other change needed for LL(1) is to give contexts a marker before they 
appear eg:

        foo :: {MonadIO m} a -> m a

By LL(1) I'm really meaning that the grammar for interactive editing needs 
to be adjusted so that it is possible to maintain the invariant that as code 
is entered from left to right constructs and identifiers can be highlighted 
according to their grammatical role and highlighting (modulo incompleteness) 
must remain unchanged regardless of whatever is typed afterwards to the 
right otherwise it can become more of a liability than a help, hence my hope 
that some future revision of Haskell grammar might consider taking the above 
points into account.

Regards, Brian.
Logic empowers us and Love gives us purpose.
Yet still phantoms restless for eras long past,
congealed in the present in unthought forms,
strive mightily unseen to destroy us.


More information about the Haskell-Cafe mailing list