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

Vesa Karvonen vesa.karvonen@cs.helsinki.fi
Thu, 14 Jul 2005 02:13:11 +0300

[[ I apologize if this is off-topic for this list. I think that the
   use of infix declarations in SML is a bit problematic, and I think
   that either language (ability to export/import infix declarations
   from/to a module) or standard library level solutions (read on)
   would be most welcome. ]]

I just reread Danvy's Functional Unparsing (http://www.brics.dk/RS/98/12/)
and took a second look at the Printf page (http://mlton.org/Printf).

Unlike Danvy's technique, the technique on the Printf page relies on a
large number of ad-hoc infix identifiers, which tends to make the
technique considerably less practical. You usually either duplicate the
infix declarations everywhere you want to use them or pollute the
top-level (or some other sufficiently wide scope) with the ad-hoc infix
declarations. There is, however, a third option.

With a couple of simple general purpose infix operators it is possible
to treat any binary function as an infix operator. See:


Thus, assuming that you would have formatter combinators named `int' and
`string', you could write

  printf (`"Here's an int "<\int\>" and a string "<\string\>".") 13 "foo"

using the infixing operators <\ and \> described in the above posting.

I frequently find uses for infix operators, but it feels awkward to use
them in SML. For instance, I thought about introducing a function like

  infix orWhenEq

  fun EQUAL orWhenEq thunk = thunk ()
    | other orWhenEq _     = other

for sequencing comparisons

  compare (a, b) orWhenEq (fn()=>
  compare (c, d) orWhenEq (fn()=>
  compare (e, f)))

(The use of thunking could probably be removed without loss of efficiency
on a "sufficiently smart compiler".) Unfortunately, this becomes
significantly less convenient unless `orWhenEq' is declared infix at the
top-level, which I find rather intrusive.

With general purpose infixing operators one could write:

  compare (a, b) <\orWhenEq\> (fn()=>
  compare (c, d) <\orWhenEq\> (fn()=>
  compare (e, f)))

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)?

Looking at Haskell libraries, they tend to use quite a lot of infix
identifiers due to the convenient x `f` y syntax.

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).

-Vesa Karvonen