[MLton] Ad-hoc infix identifiers, Printf, and libraries

Matthew Fluet fluet@cs.cornell.edu
Wed, 13 Jul 2005 20:06:14 -0400 (EDT)


> [[ I apologize if this is off-topic for this list. 

Most any aspect of SML is on-topic, though you might also bounce/cc to 
MLton-user.

> With a couple of simple general purpose infix operators it is possible
> to treat any binary function as an infix operator. See:
>  
> http://groups.google.fi/groups?hl=fi&lr=&th=2466da2429f0bd31&seekm=db10kn%24aaa%241%40oravannahka.helsinki.fi&frame=off

I thought that was very cool.  I've been very jealous of Haskell's `id` 
infix syntax, and I think <\id\> is fairly concise.  I had also forgotten 
about the sectioning functions, which are also great.  I find that I often 
riddle my code with

  Vector.equals(v, fn x => Elem.equals (x, y))

and

  Vector.equals(v, Elem.equals /> y)

is a pleasant alternative, if only because it saves me from inventing 
another identifier.

Another advantage of <\id\> is that there is no problem with <\Long.id\>, 
which can save you from opening a structure or rebinding a value just to 
use it infix.

> I frequently find uses for infix operators, but it feels awkward to use
> them in SML. 
> Unfortunately, this becomes
> significantly less convenient unless `orWhenEq' is declared infix at the
> top-level, which I find rather intrusive.

What is the intrusion?  Just the fact that your set of top-level infix 
declarations may conflict with someone elses and there isn't a good way to 
pick and choose?  Or the fact that they must be in scope everywhere?

> So, I have been thinking about infix declarations lately and I'm wondering
> about what others think about them. Do you tend to avoid infix operators
> due to the difficulties? How do you deal with the infix operators that you
> choose to provide in a library? What do you think about having general
> purpose infixing operators (like the operators <\ and \> used above)?

It seems as though infix identifiers are used rarely.  I see exactly one 
one use in the mlton sources (excluding the Basis Library declarations).

I think the real difficulty is the one you've noted -- that a library
can't package infix declarations into the signature/structure language.
Hence, it has to rely upon extra-lingual mechanisms to make identifiers
infix.  This mechanism can be something like the ML Basis system or it can
be as primitive as a comment in the library highlighting the right
cut-n-paste declarations to copy into each source file using the library.

> I noticed that the ML Basis system allows some scoping of infix
> declarations, but it is MLton specific. Also, as the mlb-files are separate
> from the sml-files, it probably makes it considerably more difficult to
> see where/whether the infix status of a specific identifier is declared (I'm
> thinking about maintenance issues here).

One of the MLKit developers was influential in the design of the ML Basis 
system, and there remains some small hope that they will also adopt it.

As to the maintenance issue, I don't think there is any more or less 
difficulty finding the binding occurrence of an identifier's infix status 
than finding the binding occurrence of an identifier.  The final "Full 
Basis" example in http://mlton.org/MLBasisExamples demonstrates how I felt 
that the system could be used to deliver a library with its infix 
bindings.  Again, there is the downside that the identifiers have infix 
status even when the library isn't opened.

The AliceML language has what appears to be a nice means of adding fixity 
status to signatures/structures:
  http://www.ps.uni-sb.de/alice/manual/modules.html#fixity

If you look at the formal specification of the ML Basis system:
  http://mlton.org/pages/MLBasis/attachments/mlb-formal.pdf
you can see that fixity environments are no problem in the formalism.  I 
suspect that AliceML's formalism/implementation works essentially the same 
way.

It is an unfortunate side-effect of the fact that Standard ML was 
conceived of as a REPL language rather than a batch compiled language that 
some issues of parsing and scoping have left us in this situation.