[MLton] optional arguments and functional record update via fold
Stephen Weeks
MLton@mlton.org
Sun, 4 Sep 2005 16:57:05 -0700
> Here is an implementation of optional arguments and functional record
> update using fold and product types.
Here is a slightly simpler implementation of the same interface.
The difference is that it uses a product of update functions, while
the previous implementation used a single update function that
interpreted a "path" to tell it which component to update. I doubt
there is any difference in practice, since everything should be
simplified away. But this one requires fewer simplifications to get
that point, so to my eye it is slightly nicer.
I forgot to mention in the previous mail that that implementation is an
improvement over earlier efforts in that the record is converted to a
product once, then all the updates are done, then the product is
converted back to a record, where earlier implementations did a pair
of conversions for each update. This implementation still has that
property. Again, this probably just means fewer simplifications to
generate the desired code.
Finally, I'll mention that all of this code is teetering on the brink
of needing first-class polymorphism, and it could certainly be cleaner
if we had it.
----------------------------------------------------------------------
datatype ('a, 'b) product = & of 'a * 'b
infix &
fun $ (a, f) = f a
fun curry f x y = f (x, y)
fun id x = x
fun pass x f = f x
structure Fold =
struct
val fold = pass
fun step0 h (a1, f) = fold (h a1, f)
fun step1 h $ a1 = step0 (curry h a1) $
fun step2 h $ a1 a2 = step0 (fn x => h (a1, a2, x)) $
end
local
local
fun lift u (p & v', v) = u (p, v) & v'
fun next f = let val (u, u') = f () in (lift u, lift u') end
in
fun u1 () = (fn (_, v) => v, fn (v2 & _, v) => v2 & v)
fun u2 () = next u1
fun u3 () = next u2
fun u4 () = next u3
end
local
fun next (m, u: unit -> 'a * 'b) f = m (f & #2 (u ()))
in
fun m1 f = f
fun m2 $ = next (m1, u1) $
fun m3 $ = next (m2, u2) $
fun m4 $ = next (m3, u3) $
end
fun make (m, u: unit -> 'a * 'b) (p2r, p2r', r2p) (f, r0) =
Fold.fold ((p2r' (m (#1 (u ()))), r2p r0), fn (_, p) => f (p2r p))
in
fun makeOpt2 $ = make (m2, u2) $
fun makeOpt3 $ = make (m3, u3) $
fun makeOpt4 $ = make (m4, u4) $
end
fun O $ = Fold.step2 (fn (s, v, (ups, p)) => (ups, s ups (p, v))) $