[MLton] using fold to write numeric constants
Stephen Weeks
MLton@mlton.org
Fri, 10 Feb 2006 07:34:58 -0800
The following code shows how to use fold to conveniently write numeric
constants in any base of various types. For example,
N i 10 `1`2`3 $
denotes 123:int in base 10, while
N ii 8 `2`3 $
denotes 19:IntInf.int in base 8.
Digits are checked dynamically to ensure they are valid for the base,
but of course MLton will simplify everything away at compile time. I
can imagine using phantom types to statically ensure validity, at the
expense of (perhaps too much) extra verbiage.
--------------------------------------------------------------------------------
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)
local
fun make (zero, op *, op +, op <, op <=, i2x, x2s) base =
let
val base = i2x base
in
(zero, fn (i, n) =>
let
val i = i2x i
in
if zero <= i 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
in
val i = make (0, op *, op +, op <, op <=, id, Int.toString)
val ii = make (0, op *, op +, op <, op <=,
IntInf.fromInt, IntInf.toString)
val w = make (0w0, op *, op +, op <, op <=,
Word.fromInt, Word.toString)
end
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