blog

The application operator in Standard ML

# April 22, 2012

In the previous post I introduced the $ operator to OCaml using two different approaches:

  1. Renaming the operator to **$ or @$ in order to achieve the necessary associativity.
  2. Leveraging Camlp4 to provide a syntax extension.

In the comments section1, variants of these operators were provided that mirror Haskell’s relative precedence of application and composition.

As a postscript, I thought it might be interesting to look at the implementation of $ in Standard ML. Here it is in the SML/NJ toplevel,

Standard ML of New Jersey v110.74 [built: Wed Apr 11 13:33:07 2012]
- infixr 0 $;
infixr $
- fun (f $ x) = f x;
val $ = fn : ('a -> 'b) * 'a -> 'b

Of note:

  • Standard ML lets us specify the associativity of newly defined operators explicitly (using the infix* fixity directives) whereas OCaml follows an operator naming convention.
  • As such, we have no need to fall back on syntax extensions here; $ is a valid name for a right associative operator.

To replicate the target example of the previous post we’ll need to define a few utilities,

- fun succ x = x + 1;
val succ = fn : int -> int
- val sum = foldl op+ 0;
val sum = fn : int list -> int
- fun printLn str = print $ str ^ "\n";
val printLn = fn : string -> unit

Note that printLn is defined using $; the standard approach would be fun printLn str = print (str ^ "\n").

With these definitions in place, we can employ $ to print the desired result:

- printLn $ Int.toString $ succ $ sum [1, 2, 3];
7
val it = () : unit

Finally, since $ was defined with a precedence level of 0, it interacts correctly with SML’s composition operator, o, which has a precedence of 3 (as per the Standard):

- printLn o Int.toString $ succ $ sum [1, 2, 3];
7
val it = () : unit

  1. See the closing Update.


comments powered by Disqus