[MLton] Structures inside a function?

Stephen Weeks MLton@mlton.org
Fri, 21 Jan 2005 07:34:10 -0800

> Hi! I recently ran into a problem where I needed to use a structure
> inside a function. However, this doesn't appear to be possible; what
> do I do instead?
> Normally, when you use a residue ring, it is a top-level construction.
> Therefore, I haven't needed this before. However, I was implementing
> Pollard's rho algorithm and then I suddenly needed a ring which was
> parameterized by a function parameter!
> I have run into this in several other places, but have always avoided
> the problem. Here, I don't see any choice other than to redefine all the
> methods I need from Math (lots) in local scope, which really sucks.

A trick I sometimes use when I'm this situation and don't want to
refactor in the other way's y'all have discussed is to use a ref cell
to delay instantiation of part of the structure.  In your case, the
lone value to be delayed is modulus, but in general, any number of
values could be delayed.  Once enough values are delayed, one can lift
the functor applications to the top level, leaving just the value part
inside the function.  For your code, this looks like

signature RESIDUE_PARAM =
      structure Base: EUCLIDEAN_DOMAIN
      val modulus: Base.t ref

functor Residue (P: RESIDUE_PARAM): RING = ...
functor Math (R: RING) = ...

functor Factor (E : EUCLIDEAN_DOMAIN) =
	 structure Base = E
	 val modulus = ref Base.zero (* dummy value *)
	 structure R = Residue (structure Base = Base
				val modulus = modulus)
	 structure M = Math (R)
	 fun factor x =
	       val () = modulus := x
	       open M
	       (* use various methods defined in Math to factor x *)

For the common case of Residue where the delaying isn't needed, you
can create a wrapper that hides the ref cell.