[MLton-user] curried function definition and pattern destructuring

Stephen Weeks sweeks@sweeks.com
Tue, 18 Jul 2006 09:12:32 -0700


> Mh, how would the difference be externally observable under the
> dynamic semantics as specified in the Definition? I believe it
> isn't.

I agree (assuming T is the only variant in its datatype).

> Consequently, it would be a valid optimization to transform the
> former into the latter.
...
> >   fun f (T {x, ...}) y = e
> >   fun f (T {x, ...}) = fn y => e

I agree (under the same proviso).  As to whether one is allowed to
transform the latter into the former, it depends on how concerned you
are about space safety.  In MLton, we are paranoid about space safety,
and want to give the programmer as much a chance as possible to reason
about the space usage of his program.  So, I'd still say that the two
are not equivalent -- MLton is allowed to asymptotically improve space
usage, but not to make it asymptotically worse.

As a MLton user, I don't want to rely on the existence of that
optimization to cut down on my space usage (in fact, MLton doesn't do
it), so I'll stick with the latter form when I need the guarantee.

> The only situation where the difference is observable is where any
> but the last curried argument contains a ref pattern, because then
> the time of dereferencing is changed by the transformation. In all
> other cases it seems to be safe.

There is one other situation where matching has a side effect -- if
the match is nonexhaustive.  For example, should the following program
silently terminate or raise Match?

  datatype t = A | B
  fun f A () = ()
  val _ = f B 

The answer is that it should silently terminate.  I just checked and
all the SML compilers get this right except for the ML Kit.