[MLton] Optional Arguments and FRU

Stephen Weeks MLton@mlton.org
Tue, 23 Aug 2005 13:50:09 -0700


> Using latest FRU techniques, OA could be done something like this:
...
>   (* A function taking optional arguments *)
>   fun f' x upds = f x (foldl op|< defs upds)
> 
> Now f' can be used like this:
> 
>    val x = f' 1 []
>    val y = f' 1 [set#b 1.0]
>    val z = f' 1 [set#a 1.0, set#c 2, set#b 1.0]
...
> I think that this compares quite favorably to the technique currently
> presented on the OA page.

It is nice.  One drawback that I see is the construction of the list
of update functions, and the consequent construction of each
intervening record by the foldl.  Unfortunately, there is no way MLton
is going to simplify that away because it doesn't optimize much
insider recursive data structures.  A slight modification of your
approach makes possible something equally concise.  If we define f'
via

  fun f' x upd = f x (upd defs)

then we can use composition of updates to avoid the list construction.

  val z = f' 1 (set#a 1.0 o set#c 2 o set#b 1.0)

I'm more confident that MLton will do the right thing here, although
not as confident as with the CPS approach.  Also, I'm not super happy
with the name "set" or "o".  To me, it would be more readable to use,
say, "opt" and "&"

  val opt = set
  infix 4 &
  val op & = op o

  val z = f' 1 (opt#a 1.0 & opt#c 2 & opt#b 1.0)

Actually, our tick (`) notation wasn't so bad either, except that one
must put a space between the tick and the hash to keep it from being
treated as one symbol

  val z = f' 1 (` #a 1.0 & ` #c 2 & ` #b 1.0)

Seeing the similarity of this and what's currently on the OA page
makes it clear that the main simplification of your proposal comes not
so much from the use of FRU techniques, but rather from the
elimination of the variable number of arguments, which requires the
CPS and $ at the end.  It is definitely much simpler to use a single
argument consisting of a function composition (or fold over list of
updaters) than to use variable argument techniques.

I wonder if in practice, since set/opt is specific to f' anyways, it
might be reasonable to name each of the optional argument updaters, so
that one could write

  val z = f' 10 (a 1.0 & c 2 & b 1.0)

> The FRU technique also allows fairly convenient syntax for calling
> the original function given just the defaults. For example:
> 
>    val x = f 1 defs
>    val y = f 1 o set#b 1.0 |< defs
>    val z = f 1 o set#a 1.0 o set#c 2 o set#b 1.0 |< defs

With my tweak, this becomes

    val x = f 1 defs
    val y = f 1 (set#b 1.0 |< defs)
    val z = f 1 (set#a 1.0 o set#c 2 o set#b 1.0 |< defs)

or even

    val z = f 1 (a 1.0 & c 2 & b 1.0 |< defs)