[MLton] A variation of functional record update notation

Stephen Weeks MLton@mlton.org
Mon, 8 Aug 2005 15:02:55 -0700


> It occured to me that if you curry the update function and reorder the
> parameters, you can use the left piping operator (http://mlton.org/InfixingOperators)
> and still have a fairly readable notation:
> 
>    record >| set#field1 value1
>           >| set#field2 value2
>           ...
>           >| set#fieldN valueN
...
> This way there is no need to define a separate infix operator for functional
> record update.

Nice.  I've been using a similar approach recently in some code where
I wanted a convenient syntax for imperative record update.  Here's an
example.  Suppose we have some object type X.t, where such objects
have a settable "n", "s", and "x" field.  Define the setters, as you
did, to be curried and to take the object last.

------------------------------------------------------------
signature X =
   sig
      type t

      val s: t
         
      structure Set:
         sig
            val n: int -> t -> unit
            val s: string -> t -> unit
            val x: real -> t -> unit
         end
   end
------------------------------------------------------------

Then, define a combinator to combine setters.

------------------------------------------------------------
infix  4 &
val op & : ('a -> unit) * ('a -> unit) -> 'a -> unit =
   fn (f, g) => fn a => (f a; g a)
------------------------------------------------------------

Now, it is easy to set whatever fields you want.

------------------------------------------------------------
functor F (X: X) =
   struct
      structure S = X.Set
      val () = X.s >| S.n 13 & S.s "foo" & S.x 17.0
   end
------------------------------------------------------------

An alternative to introducing the new infix "&" operator is to change
the type of the setters to return the object.  Then, one could just
use pipe, as in

      val _ = X.s >| S.n 13 >| S.s "foo" >| S.x 17.0

But I find the "&" combinator useful because one can treat collections
of attributes as a single attribute, and share it across multiple
objects, as in

      val a = S.n 13 & S.s "foo"
      val () = X.s1 >| a & S.x 17.0
      val () = X.s2 >| a & S.x 19.0

> Do you think that it would make sense to provide a simple script
> (maybe Emacs lisp) to generate a signature/structure (say
> RECORDS/Records) of makeSetter -functions (upto desired N) and
> change the FRU-page to use the piping notation?

I have no objection to the page being changed.  I think the new
approach is more useful too.  The fewer infixes the better.