[MLton] handling a variable number of arguments in SML

Stephen Weeks MLton@mlton.org
Tue, 23 Aug 2005 15:48:12 -0700


> the simplest version I could come up with, which shows how to define
> a function "f" that takes a variable number of "a" arguments, and
> when it receives the end of arguments marker, "$", returns the
> number of "a"s it received.

The approach can be generalized to allow one to define a fold
function that takes a variable number of arguments.

----------------------------------------------------------------------
signature S =
   sig
      type ('a, 'b, 'k) v
      type ('a, 'b, 'k) u = ('a, 'b, 'k) v -> 'k

      val $ : ('a, 'b, 'b) v
      val fold: 'b * ('a * 'b -> 'b) -> ('a, 'b, 'k) u
      val a: 'a -> ('a, 'b, ('a, 'b, 'k) u) v
   end

functor F (S: S) =
   struct
      open S

      fun p i = print (concat [Int.toString i, "\n"])
      val () = p (fold (0, op +) (a 1) (a 2) (a 3) $)
   end
  
structure S: S =
   struct
      type ('a, 'b, 'k) v = 'b * ('a * 'b -> 'b) -> 'k
      type ('a, 'b, 'k) u = ('a, 'b, 'k) v -> 'k

      fun $ (b, _) = b
      fun fold z v = v z
      fun a x (b, f) v = v (f (x, b), f)
   end

structure Z = F (S)
----------------------------------------------------------------------

This has one advantage over the usual List.fold because MLton will
simplify away all the continuation stuff and will thus be encourage to
compute the fold at compile time.  For example, in the above, I would
bet that the sum, 6, is computed at compile time.

I'm unsure of what advantage, if any, the continuation approach has
over the composition-of-arguments approach.

----------------------------------------------------------------------
infix 4 &
signature S =
   sig
      type ('a, 'b) arg

      val & : ('a, 'b) arg * ('a, 'b) arg -> ('a, 'b) arg
      val fold: 'b * ('a * 'b -> 'b) -> ('a, 'b) arg -> 'b
      val a: 'a -> ('a, 'b) arg
   end

functor F (S: S) =
   struct
      open S

      fun p i = print (concat [Int.toString i, "\n"])
      val () = p (fold (0, op +) (a 1 & a 2 & a 3))
   end
  
structure S: S =
   struct
      type ('a, 'b) z = 'b * ('a * 'b -> 'b) 
      type ('a, 'b) arg = ('a, 'b) z -> ('a, 'b) z

      val op & = op o
      fun fold z (v: ('a, 'b) arg) = #1 (v z)
      fun a x (b, f) = (f (x, b), f)
   end

structure Z = F (S)
----------------------------------------------------------------------