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

Benjamin Franksen benjamin.franksen at bessy.de
Thu Sep 28 17:05:28 EDT 2006


Brian Hulley wrote:
> 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:
> 
>     let
>         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:
> 
>     let
>         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 function.
> 
> However the current syntax of Haskell would not allow this. Instead you
> have to write:
> 
>     let
>         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'.

Sorry, but I can't see the problem here. Why can't the editor offer the
operator as '!' in the list of options, and if the user selects it insert
both '(' and ')' at the right places (i.e. before the module name and after
the operator)? Is there some unwritten law that forbids editors or IDEs to
insert stuff at positions other than the current cursor position?

Isn't Haskell (assuming you are programming your editor in Haskell) not
supposed to make hard things easy(er)? Rather than complain about libraries
that offer operators (which i personally like very much, thank you) or
proposing to change the language, use your imagination and design a new
human interface that deals with the language in the most useful way. [BTW,
I recommend you take a look at what Conor BcBride did to support 'visual'
(dependently typed) programming in Epigram. There's many good ideas there
to steal from ;)]

Generally speaking, I would always hesitate to change the language so it
better suits programming tools(*). It is the tools which should adapt to
the language, even if that means the programmer has to find new ways of
suporting the user (and the language). The most important reason being that
code is more often read than written.

That said, there still might be good arguments to change the syntax in the
way you propose, just not the one you gave above. In fact, I am half of a
mind to say I like Data.Array.IArray.(!) better than (Data.Array.IArray.!).
My reason is that the former is more readable because it highlights the
operator symbol by surrounding it with parentheses, whereas the latter
obscures it.

At the danger of becoming completely off-topic now (sorry!), I have to say
that I find /both/ versions ugly and unnecessarily hard to read. My
personal solution is to generally avoid qualified imports. I use it only if
absolutely necessary to disambiguate some symbol, and then just for that
symbol. I am aware that there is an opposing faction here, who tries to
convinve everyone that qualified import should be the standard (and the
actual exported symbols --at least some of them-- meaningless, such as 'C'
or 'T'). I think such a convention is inappropriate for a functional
language (especially one with user defined operators). There simply is no
natural 1:1 correspondence between data type declaration and functions
acting on that data built into the language, as opposed to e.g. OO
languages. Extensibility in the functional dimension, i.e. the ability to
arbitrarily add functions that operate on some data without having to
change the code (module) that defines the data, is one of the hallmarks of
functional programming, as opposed to OO programming.(**)

Cheers
Ben
--
(*) Yes I know it has at least to be compilable, preferably in an efficient
way. However, that doesn't invalidate the argument. Indeed, it is bad
enough that we have to compromise in order to make our languages
implementable with current compiler technology. No need to compromise on
much less essential equipment, such as syntax aware editing tools.

(**) One could argue that this extensibility is lost anyway as soon
as /abstract/ data types come into play. However, [warning: it gets even
more off-topic from here on] nothing prevents us from offering /two/
interfaces (visible modules), one where the data type is abstract ("client
interface") and a different one where it is concrete ("extension
interface"). Of course, only the abstract (client) interface guarantees
that invariants cannot be broken by the user code. But that doesn't mean a
concrete interface wouldn't be useful. How often have there been requests
to add this or that function to some standard library abstract data type?
If the concrete type would be available via an extension interface, users
who need additional functions that operate directly on the underlying data
structure (for instance for efficiency reasons) could then build and also
publish such extension modules (with, again, an abstract interface so usage
is safe). [I am aware that this can lead to maintenance problems if the
internal data type or invariants get changed. I still think it is better to
have the possibility to add new functions (and live with eventual
consequences) than to not have it.]



More information about the Haskell-Cafe mailing list