[MLton] Slightly simpler functional record update

Stephen Weeks MLton@mlton.org
Fri, 12 Aug 2005 09:26:19 -0700


> Thinking about the functional record update technique, a couple of
> things occured to me. First of all, functional record update makes
> sense for plain tuples (which are really a form of record in SML).

Sure.

> Also, the `fruN' (or the `makeSetterN') functions seem to be doing
> two separable things: 
> - perform a "functional tuple update", and
> - convert from a record to a tuple and back.

Makes sense.

> Then I wrote a `set' function for the record {a, b, c} using `set3':
> 
>   fun set f v {a = v1, b = v2, c = v3} =
>       let
>          fun r (v1, v2, v3) = {a = v1, b = v2, c = v3}
>       in
>          r (set3 (f o r) v (v1, v2, v3))
>       end
...
> This formulation is slightly simpler (meaning the implementation requires
> slightly less code) than the one based on `fruN' (or `makeSetterN') functions.
> In addition, the functional tuple update, `setN', operations can be useful
> on their own.
>
> I think that this formulation may also be a bit easier to
> understand, because the conversions (tuple <-> record) and the tuple
> update are now separated (and can be understood on their own). Also,
> there is no need to mention first class (or rank-2) polymorphism.

Even with your improvement, I find the construction 

  r (set3 (f o r) v (v1, v2, v3))

in the definition of set complicated enough to be worth abstracting
into a makeSetter3 function.  I like separating the update from the
conversions, but I think it makes the isomorphism clearer to define
the set function via makeSetter3 as follows.

----------------------------------------------------------------------
fun makeSetter3 (r1, r2, t) f z s = r1 (set3 (f o r2) z (t s))
   
fun set f =
   let
      fun r (a, b, c) = {a = a, b = b, c = c}
      fun t {a, b, c} = (a, b, c)
   in
      makeSetter3 (r, r, t) f
   end
----------------------------------------------------------------------

It's a shame about the lack of first-class polymorphism, but I don't
think it's worth sacrificing the abstraction because of its absence.
Besides, it servers a nice reminder to those newer to SML that there
are things beyond.