[MLton] using fold to write numeric constants

Stephen Weeks MLton@mlton.org
Fri, 10 Feb 2006 10:08:18 -0800


> Looking briefly at the code, I noticed a minor simplification:
> 
> >          fun make (zero, op *, op +, op <, op <=, i2x, x2s) base =
>                                        ^^^^  ^^^^^
> 
> Only one of those is needed.
...
> The `zero' could also be eliminated easily.
...
> This would be a useful simplification (from the user's point-of-view) if the
> `make' function would not be local.

Good catches.  It does make sense for "make" to be exported, so that
the code can be used for user-specified types.

--------------------------------------------------------------------------------

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 $ x = step0 (curry h x) $
   end

structure Num =
   struct
      fun N ty base = Fold.fold (ty base, fn (n, _) => n)

      fun make (op *, op +, op <, i2x, x2s) base =
         let
            val zero = i2x 0
            val base = i2x base
         in
            (zero, fn (i, n) =>
             let
                val i = i2x i
             in
                if not (i < zero) andalso i < base then
                   n * base + i
                else
                   raise Fail (concat
                               ["Num: ", x2s i,
                                " is not a valid digit in base ", x2s base])
             end)
         end

      val i = make (op *, op +, op <, id, Int.toString)
      val ii = make (op *, op +, op <, IntInf.fromInt, IntInf.toString)
      val w = make (op *, op +, op <, Word.fromInt, Word.toString)

      fun ` z = Fold.step1 (fn (i, (ac, step)) => (step (i, ac), step)) z

      val a = 10
      val b = 11
      val c = 12
      val d = 13
      val e = 14
      val f = 15
   end

local
   fun make x2s x = print (concat [x2s x, "\n"])
in
   val pi = make Int.toString
   val pii = make IntInf.toString
   val pw = make Word.toString
end

local
   open Num
in
   val () = pi (N i 10 `1`2`3 $)
   val () = pii (N ii 10 `1`2`3`4`5`6`7`8`9`0`1`2 $)
   val () = pw (N w 16 `1`b $)
   val () = pi (N i 12 `1`a $)
   val () = pii (N ii 8 `2`3 $)
   val () = pw (N w 2 `1`1`0 $)
end