4 Numeric literals in <:StandardML:Standard ML> can be written in either
5 decimal or hexadecimal notation. Sometimes it can be convenient to
6 write numbers down in other bases. Fortunately, using <:Fold:>, it is
7 possible to define a concise syntax for numeric literals that allows
8 one to write numeric constants in any base and of various types
9 (`int`, `IntInf.int`, `word`, and more).
11 We will define constants `I`, `II`, `W`, and +`+ so
17 denotes `123:int` in base 10, while
22 denotes `19:IntInf.int` in base 8, and
35 fun make (op *, op +, i2x) iBase =
42 if 0 <= i andalso i < iBase then
46 ["Num: ", Int.toString i,
49 Int.toString iBase])),
53 fun I ? = make (op *, op +, id) ?
54 fun II ? = make (op *, op +, IntInf.fromInt) ?
55 fun W ? = make (op *, op +, Word.fromInt) ?
57 fun ` ? = Fold.step1 (fn (i, (x, step)) =>
58 (step (i, x), step)) ?
74 The idea is for the fold to start with zero and to construct the
75 result one digit at a time, with each stepper multiplying the previous
76 result by the base and adding the next digit. The code is abstracted
77 in two different ways for extra generality. First, the `make`
78 function abstracts over the various primitive operations (addition,
79 multiplication, etc) that are needed to construct a number. This
80 allows the same code to be shared for constants `I`, `II`, `W` used to
81 write down the various numeric types. It also allows users to add new
82 constants for additional numeric types, by supplying the necessary
85 Second, the step function, +`+, is abstracted over the actual
86 construction operation, which is created by make, and passed along the
87 fold. This allows the same constant, +`+, to be used for all
88 numeric types. The alternative approach, having a different step
89 function for each numeric type, would be more painful to use.
91 On the surface, it appears that the code checks the digits dynamically
92 to ensure they are valid for the base. However, MLton will simplify
93 everything away at compile time, leaving just the final numeric