Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / integer.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2009 Matthew Fluet.
2 * Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 *)
8
9functor Integer (S: INTEGER_STRUCTS): INTEGER =
10struct
11
12open S
13
14structure In = In0
15
16structure Int =
17 struct
18 open S
19
20 type t = int
21
22 val zero = fromInt 0
23
24 val layout = Layout.str o toString
25
26 val equals = op =
27 end
28
29structure R =
30 OrderedRing (structure R =
31 RingWithIdentity (structure R = Ring (Int)
32 open R S
33 val one = fromInt 1)
34 open R S
35 val {compare, ...} =
36 Relation.lessEqual {< = op <, equals = equals})
37open R S
38
39exception Input
40fun input i = (In.ignoreSpaces i
41 ; (case fromString (In.inputToSpace i) of
42 NONE => raise Input
43 | SOME n => n))
44
45structure I = EuclideanRing (open R S
46 val metric = toIntInf o abs
47 val monics = Stream.infinite (two, fn n => n + one)
48 val unitEquivalent = abs)
49open I
50
51fun isEven n = isZero (n mod two)
52
53val isOdd = not o isEven
54
55fun toCommaString n =
56 let
57 fun loop (chars, accum) =
58 let
59 fun done () = implode (rev chars @ accum)
60 in
61 case chars of
62 x1 :: x2 :: x3 :: chars =>
63 (case chars of
64 [] => done ()
65 | [#"~"] => done ()
66 | _ => loop (chars, #"," :: x3 :: x2 :: x1 :: accum))
67 | _ => done ()
68 end
69 in loop (rev (explode (toString n)), [])
70 end
71
72fun choose (n, k) =
73 let val k = max (k, n - k)
74 in prodFromTo {from = add1 k, to = n, term = fn i => i}
75 div factorial (n - k)
76 end
77
78fun output (n, out) = Out.output (out, toString n)
79
80fun largest (i, f) =
81 let
82 fun loop (n: t) =
83 if f n
84 then n
85 else loop (sub1 n)
86 in
87 loop i
88 end
89
90fun smallest (i, f) =
91 let
92 fun loop (n: t) =
93 if f n
94 then n
95 else loop (add1 n)
96 in loop i
97 end
98
99fun least (start: t, stop: t, f: int -> bool): int option =
100 let
101 fun loop (i: t) =
102 if i >= stop
103 then NONE
104 else if f i
105 then SOME i
106 else loop (i + one)
107 in loop start
108 end
109
110fun 'a fold (start: t, stop: t, a: 'a, f: int * 'a -> 'a): 'a =
111 let
112 val _ = Assert.assert ("Integer.fold", fn () => start <= stop + one)
113 fun loop (i: t, a: 'a): 'a =
114 if i >= stop
115 then a
116 else loop (i + one, f (i, a))
117 in loop (start, a)
118 end
119
120fun forall (start: t, stop: t, f: int -> bool): bool =
121 Exn.withEscape
122 (fn escape => (fold (start, stop, (), fn (i, ()) =>
123 if f i then () else escape false)
124 ; true))
125
126fun exists (start, stop, f) = not (forall (start, stop, not o f))
127
128fun 'a foldDown (start: t, stop: t, a: 'a, f: int * 'a -> 'a): 'a =
129 let
130 val _ = Assert.assert ("Integer.foldDown", fn () => start <= stop + one)
131 fun loop (i: t, a: 'a) =
132 if i < start
133 then a
134 else loop (sub1 i, f (i, a))
135 in loop (sub1 stop, a)
136 end
137
138fun map (start: t, stop: t, f: t -> 'a): 'a list =
139 foldDown (start, stop, [], fn (i, l) => f i :: l)
140
141fun for (start: t, stop: t, f: t -> unit): unit =
142 fold (start, stop, (), f o #1)
143
144fun forDown (start: t, stop: t, f: t -> unit): unit =
145 foldDown (start, stop, (), f o #1)
146
147fun scan (radix, reader) = Int.scan radix reader
148
149fun format (i, r) = fmt r i
150
151end