trackler 2.2.1.16 → 2.2.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/delphi/config/maintainers.json +1 -1
  4. data/tracks/objective-c/docs/SNIPPET.txt +10 -0
  5. data/tracks/python/.gitignore +1 -0
  6. data/tracks/python/exercises/accumulate/accumulate.py +1 -1
  7. data/tracks/python/exercises/allergies/allergies.py +9 -1
  8. data/tracks/python/exercises/alphametics/alphametics.py +1 -1
  9. data/tracks/python/exercises/anagram/anagram.py +1 -1
  10. data/tracks/python/exercises/atbash-cipher/atbash_cipher.py +2 -2
  11. data/tracks/python/exercises/beer-song/beer_song.py +2 -2
  12. data/tracks/python/exercises/binary/binary.py +1 -1
  13. data/tracks/python/exercises/binary-search/binary_search.py +1 -1
  14. data/tracks/python/exercises/bob/bob.py +1 -1
  15. data/tracks/python/exercises/book-store/book_store.py +1 -1
  16. data/tracks/python/exercises/bracket-push/bracket_push.py +1 -1
  17. data/tracks/python/requirements-travis.txt +1 -1
  18. data/tracks/rust/config.json +21 -7
  19. data/tracks/rust/exercises/crypto-square/.gitignore +7 -0
  20. data/tracks/rust/exercises/crypto-square/Cargo-example.toml +7 -0
  21. data/tracks/rust/exercises/crypto-square/Cargo.toml +6 -0
  22. data/tracks/rust/exercises/crypto-square/README.md +106 -0
  23. data/tracks/rust/exercises/crypto-square/example.rs +114 -0
  24. data/tracks/rust/exercises/crypto-square/src/lib.rs +3 -0
  25. data/tracks/rust/exercises/crypto-square/tests/crypto-square.rs +81 -0
  26. data/tracks/sml/Makefile +1 -1
  27. data/tracks/sml/config.json +30 -0
  28. data/tracks/sml/exercises/atbash-cipher/README.md +64 -0
  29. data/tracks/sml/exercises/atbash-cipher/atbash-cipher.sml +5 -0
  30. data/tracks/sml/exercises/atbash-cipher/example.sml +32 -0
  31. data/tracks/sml/exercises/atbash-cipher/test.sml +52 -0
  32. data/tracks/sml/exercises/atbash-cipher/testlib.sml +159 -0
  33. data/tracks/sml/exercises/pangram/README.md +45 -0
  34. data/tracks/sml/exercises/pangram/example.sml +18 -0
  35. data/tracks/sml/exercises/pangram/pangram.sml +2 -0
  36. data/tracks/sml/exercises/pangram/test.sml +41 -0
  37. data/tracks/sml/exercises/pangram/testlib.sml +159 -0
  38. data/tracks/sml/exercises/perfect-numbers/README.md +54 -0
  39. data/tracks/sml/exercises/perfect-numbers/example.sml +26 -0
  40. data/tracks/sml/exercises/perfect-numbers/perfect-numbers.sml +6 -0
  41. data/tracks/sml/exercises/perfect-numbers/test.sml +59 -0
  42. data/tracks/sml/exercises/perfect-numbers/testlib.sml +159 -0
  43. metadata +24 -1
@@ -0,0 +1,32 @@
1
+ fun chunkify chunkSz s =
2
+ let
3
+ val sz = size s
4
+
5
+ fun chunker 0 _ = chunker chunkSz (substring (s, 0, chunkSz))
6
+ | chunker i acc =
7
+ if sz = i
8
+ then acc
9
+ else if sz - i < chunkSz
10
+ then acc ^ " " ^ substring (s, i, size s - i)
11
+ else chunker (i + chunkSz) (acc ^ " " ^ substring (s, i, chunkSz))
12
+ in
13
+ if chunkSz > sz
14
+ then s
15
+ else chunker 0 ""
16
+ end
17
+
18
+ fun cipher c =
19
+ let
20
+ open Char
21
+ val n = ord #"z" + ord #"a"
22
+ val c = toLower c
23
+ in
24
+ if isAlpha c
25
+ then (toString o chr) (n - ord c)
26
+ else if isDigit c
27
+ then toString c
28
+ else ""
29
+ end
30
+
31
+ val decode = String.translate cipher
32
+ val encode = (chunkify 5) o decode
@@ -0,0 +1,52 @@
1
+ (* version 1.0.0 *)
2
+
3
+ use "atbash-cipher.sml";
4
+ use "testlib.sml";
5
+
6
+ infixr |>
7
+ fun x |> f = f x
8
+
9
+ val testsuite =
10
+ describe "atbash-cipher" [
11
+ describe "encode" [
12
+ test "encode yes"
13
+ (fn _ => encode ("yes") |> Expect.equalTo "bvh"),
14
+
15
+ test "encode no"
16
+ (fn _ => encode ("no") |> Expect.equalTo "ml"),
17
+
18
+ test "encode OMG"
19
+ (fn _ => encode ("OMG") |> Expect.equalTo "lnt"),
20
+
21
+ test "encode spaces"
22
+ (fn _ => encode ("O M G") |> Expect.equalTo "lnt"),
23
+
24
+ test "encode mindblowingly"
25
+ (fn _ => encode ("mindblowingly") |> Expect.equalTo "nrmwy oldrm tob"),
26
+
27
+ test "encode numbers"
28
+ (fn _ => encode ("Testing,1 2 3, testing.") |> Expect.equalTo "gvhgr mt123 gvhgr mt"),
29
+
30
+ test "encode deep thought"
31
+ (fn _ => encode ("Truth is fiction.") |> Expect.equalTo "gifgs rhurx grlm"),
32
+
33
+ test "encode all the letters"
34
+ (fn _ => encode ("The quick brown fox jumps over the lazy dog.") |> Expect.equalTo "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt")
35
+ ],
36
+
37
+ describe "decode" [
38
+ test "decode exercism"
39
+ (fn _ => decode ("vcvix rhn") |> Expect.equalTo "exercism"),
40
+
41
+ test "decode a sentence"
42
+ (fn _ => decode ("zmlyh gzxov rhlug vmzhg vkkrm thglm v") |> Expect.equalTo "anobstacleisoftenasteppingstone"),
43
+
44
+ test "decode numbers"
45
+ (fn _ => decode ("gvhgr mt123 gvhgr mt") |> Expect.equalTo "testing123testing"),
46
+
47
+ test "decode all the letters"
48
+ (fn _ => decode ("gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt") |> Expect.equalTo "thequickbrownfoxjumpsoverthelazydog")
49
+ ]
50
+ ]
51
+
52
+ val _ = Test.run testsuite
@@ -0,0 +1,159 @@
1
+ structure Expect =
2
+ struct
3
+ datatype expectation = Pass | Fail of string * string
4
+
5
+ local
6
+ fun failEq b a =
7
+ Fail ("Expected: " ^ b, "Got: " ^ a)
8
+
9
+ fun failExn b a =
10
+ Fail ("Expected: " ^ b, "Raised: " ^ a)
11
+
12
+ fun exnName (e: exn): string = General.exnName e
13
+ in
14
+ fun truthy a =
15
+ if a
16
+ then Pass
17
+ else failEq "true" "false"
18
+
19
+ fun falsy a =
20
+ if a
21
+ then failEq "false" "true"
22
+ else Pass
23
+
24
+ fun equalTo b a =
25
+ if a = b
26
+ then Pass
27
+ else failEq (PolyML.makestring b) (PolyML.makestring a)
28
+
29
+ fun nearTo b a =
30
+ if Real.== (a, b)
31
+ then Pass
32
+ else failEq (Real.toString b) (Real.toString a)
33
+
34
+ fun anyError f =
35
+ (
36
+ f ();
37
+ failExn "an exception" "Nothing"
38
+ ) handle _ => Pass
39
+
40
+ fun error e f =
41
+ (
42
+ f ();
43
+ failExn (exnName e) "Nothing"
44
+ ) handle e' => if exnMessage e' = exnMessage e
45
+ then Pass
46
+ else failExn (exnMessage e) (exnMessage e')
47
+ end
48
+ end
49
+
50
+ structure TermColor =
51
+ struct
52
+ datatype color = Red | Green | Yellow | Normal
53
+
54
+ fun f Red = "\027[31m"
55
+ | f Green = "\027[32m"
56
+ | f Yellow = "\027[33m"
57
+ | f Normal = "\027[0m"
58
+
59
+ fun colorize color s = (f color) ^ s ^ (f Normal)
60
+
61
+ val redit = colorize Red
62
+
63
+ val greenit = colorize Green
64
+
65
+ val yellowit = colorize Yellow
66
+ end
67
+
68
+ structure Test =
69
+ struct
70
+ datatype testnode = TestGroup of string * testnode list
71
+ | Test of string * (unit -> Expect.expectation)
72
+
73
+ local
74
+ datatype evaluation = Success of string
75
+ | Failure of string * string * string
76
+ | Error of string * string
77
+
78
+ fun indent n s = (implode (List.tabulate (n, fn _ => #" "))) ^ s
79
+
80
+ fun fmt indentlvl ev =
81
+ let
82
+ val check = TermColor.greenit "\226\156\148 " (* ✔ *)
83
+ val cross = TermColor.redit "\226\156\150 " (* ✖ *)
84
+ val indentlvl = indentlvl * 2
85
+ in
86
+ case ev of
87
+ Success descr => indent indentlvl (check ^ descr)
88
+ | Failure (descr, exp, got) =>
89
+ String.concatWith "\n" [indent indentlvl (cross ^ descr),
90
+ indent (indentlvl + 2) exp,
91
+ indent (indentlvl + 2) got]
92
+ | Error (descr, reason) =>
93
+ String.concatWith "\n" [indent indentlvl (cross ^ descr),
94
+ indent (indentlvl + 2) (TermColor.redit reason)]
95
+ end
96
+
97
+ fun eval (TestGroup _) = raise Fail "Only a 'Test' can be evaluated"
98
+ | eval (Test (descr, thunk)) =
99
+ (
100
+ case thunk () of
101
+ Expect.Pass => ((1, 0, 0), Success descr)
102
+ | Expect.Fail (s, s') => ((0, 1, 0), Failure (descr, s, s'))
103
+ )
104
+ handle e => ((0, 0, 1), Error (descr, "Unexpected error: " ^ exnMessage e))
105
+
106
+ fun flatten depth testnode =
107
+ let
108
+ fun sum (x, y, z) (a, b, c) = (x + a, y + b, z + c)
109
+
110
+ fun aux (t, (counter, acc)) =
111
+ let
112
+ val (counter', texts) = flatten (depth + 1) t
113
+ in
114
+ (sum counter' counter, texts :: acc)
115
+ end
116
+ in
117
+ case testnode of
118
+ TestGroup (descr, ts) =>
119
+ let
120
+ val (counter, texts) = foldr aux ((0, 0, 0), []) ts
121
+ in
122
+ (counter, (indent (depth * 2) descr) :: List.concat texts)
123
+ end
124
+ | Test _ =>
125
+ let
126
+ val (counter, evaluation) = eval testnode
127
+ in
128
+ (counter, [fmt depth evaluation])
129
+ end
130
+ end
131
+
132
+ fun println s = print (s ^ "\n")
133
+ in
134
+ fun run suite =
135
+ let
136
+ val ((succeeded, failed, errored), texts) = flatten 0 suite
137
+
138
+ val summary = String.concatWith ", " [
139
+ TermColor.greenit ((Int.toString succeeded) ^ " passed"),
140
+ TermColor.redit ((Int.toString failed) ^ " failed"),
141
+ TermColor.redit ((Int.toString errored) ^ " errored"),
142
+ (Int.toString (succeeded + failed + errored)) ^ " total"
143
+ ]
144
+
145
+ val status = if failed = 0 andalso errored = 0
146
+ then OS.Process.success
147
+ else OS.Process.failure
148
+
149
+ in
150
+ List.app println texts;
151
+ println "";
152
+ println ("Tests: " ^ summary);
153
+ OS.Process.exit status
154
+ end
155
+ end
156
+ end
157
+
158
+ fun describe description tests = Test.TestGroup (description, tests)
159
+ fun test description thunk = Test.Test (description, thunk)
@@ -0,0 +1,45 @@
1
+ # Pangram
2
+
3
+ Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma,
4
+ "every letter") is a sentence using every letter of the alphabet at least once.
5
+ The best known English pangram is:
6
+ > The quick brown fox jumps over the lazy dog.
7
+
8
+ The alphabet used consists of ASCII letters `a` to `z`, inclusive, and is case
9
+ insensitive. Input will not contain non-ASCII symbols.
10
+
11
+ ## Loading your exercise implementation in PolyML
12
+
13
+ ```
14
+ $ poly --use {exercise}.sml
15
+ ```
16
+
17
+ Or:
18
+
19
+ ```
20
+ $ poly
21
+ > use "{exercise}.sml";
22
+ ```
23
+
24
+ **Note:** You have to replace {exercise}.
25
+
26
+ ## Running the tests
27
+
28
+ ```
29
+ $ poly -q --use test.sml
30
+ ```
31
+
32
+ ## Feedback, Issues, Pull Requests
33
+
34
+ The [exercism/sml](https://github.com/exercism/sml) repository on
35
+ GitHub is the home for all of the Standard ML exercises.
36
+
37
+ If you have feedback about an exercise, or want to help implementing a new
38
+ one, head over there and create an issue. We'll do our best to help you!
39
+
40
+ ## Source
41
+
42
+ Wikipedia [https://en.wikipedia.org/wiki/Pangram](https://en.wikipedia.org/wiki/Pangram)
43
+
44
+ ## Submitting Incomplete Solutions
45
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,18 @@
1
+ fun isPangram (input: string): bool =
2
+ let
3
+ val counter = Array.tabulate (26, fn _ => 0)
4
+ val chars = map Char.toLower (String.explode input)
5
+ val aCode = ord #"a"
6
+
7
+ fun updateCounter c =
8
+ let
9
+ val index = ord c - aCode
10
+ in
11
+ if index < 0
12
+ then ()
13
+ else Array.update (counter, index, (Array.sub (counter, index)) + 1)
14
+ end
15
+ in
16
+ List.app updateCounter chars;
17
+ Array.all (fn x => x > 0) counter
18
+ end
@@ -0,0 +1,2 @@
1
+ fun isPangram (input: string): bool =
2
+ raise Fail "'isPangram' is not implemented"
@@ -0,0 +1,41 @@
1
+ (* version 1.1.0 *)
2
+
3
+ use "pangram.sml";
4
+ use "testlib.sml";
5
+
6
+ infixr |>
7
+ fun x |> f = f x
8
+
9
+ val testsuite =
10
+ describe "pangram" [
11
+ describe "Check if the given string is an pangram" [
12
+ test "sentence empty"
13
+ (fn _ => isPangram ("") |> Expect.falsy),
14
+
15
+ test "pangram with only lower case"
16
+ (fn _ => isPangram ("the quick brown fox jumps over the lazy dog") |> Expect.truthy),
17
+
18
+ test "missing character 'x'"
19
+ (fn _ => isPangram ("a quick movement of the enemy will jeopardize five gunboats") |> Expect.falsy),
20
+
21
+ test "another missing character 'x'"
22
+ (fn _ => isPangram ("the quick brown fish jumps over the lazy dog") |> Expect.falsy),
23
+
24
+ test "pangram with underscores"
25
+ (fn _ => isPangram ("the_quick_brown_fox_jumps_over_the_lazy_dog") |> Expect.truthy),
26
+
27
+ test "pangram with numbers"
28
+ (fn _ => isPangram ("the 1 quick brown fox jumps over the 2 lazy dogs") |> Expect.truthy),
29
+
30
+ test "missing letters replaced by numbers"
31
+ (fn _ => isPangram ("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog") |> Expect.falsy),
32
+
33
+ test "pangram with mixed case and punctuation"
34
+ (fn _ => isPangram ("\"Five quacking Zephyrs jolt my wax bed.\"") |> Expect.truthy),
35
+
36
+ test "upper and lower case versions of the same character should not be counted separately"
37
+ (fn _ => isPangram ("the quick brown fox jumps over with lazy FX") |> Expect.falsy)
38
+ ]
39
+ ]
40
+
41
+ val _ = Test.run testsuite
@@ -0,0 +1,159 @@
1
+ structure Expect =
2
+ struct
3
+ datatype expectation = Pass | Fail of string * string
4
+
5
+ local
6
+ fun failEq b a =
7
+ Fail ("Expected: " ^ b, "Got: " ^ a)
8
+
9
+ fun failExn b a =
10
+ Fail ("Expected: " ^ b, "Raised: " ^ a)
11
+
12
+ fun exnName (e: exn): string = General.exnName e
13
+ in
14
+ fun truthy a =
15
+ if a
16
+ then Pass
17
+ else failEq "true" "false"
18
+
19
+ fun falsy a =
20
+ if a
21
+ then failEq "false" "true"
22
+ else Pass
23
+
24
+ fun equalTo b a =
25
+ if a = b
26
+ then Pass
27
+ else failEq (PolyML.makestring b) (PolyML.makestring a)
28
+
29
+ fun nearTo b a =
30
+ if Real.== (a, b)
31
+ then Pass
32
+ else failEq (Real.toString b) (Real.toString a)
33
+
34
+ fun anyError f =
35
+ (
36
+ f ();
37
+ failExn "an exception" "Nothing"
38
+ ) handle _ => Pass
39
+
40
+ fun error e f =
41
+ (
42
+ f ();
43
+ failExn (exnName e) "Nothing"
44
+ ) handle e' => if exnMessage e' = exnMessage e
45
+ then Pass
46
+ else failExn (exnMessage e) (exnMessage e')
47
+ end
48
+ end
49
+
50
+ structure TermColor =
51
+ struct
52
+ datatype color = Red | Green | Yellow | Normal
53
+
54
+ fun f Red = "\027[31m"
55
+ | f Green = "\027[32m"
56
+ | f Yellow = "\027[33m"
57
+ | f Normal = "\027[0m"
58
+
59
+ fun colorize color s = (f color) ^ s ^ (f Normal)
60
+
61
+ val redit = colorize Red
62
+
63
+ val greenit = colorize Green
64
+
65
+ val yellowit = colorize Yellow
66
+ end
67
+
68
+ structure Test =
69
+ struct
70
+ datatype testnode = TestGroup of string * testnode list
71
+ | Test of string * (unit -> Expect.expectation)
72
+
73
+ local
74
+ datatype evaluation = Success of string
75
+ | Failure of string * string * string
76
+ | Error of string * string
77
+
78
+ fun indent n s = (implode (List.tabulate (n, fn _ => #" "))) ^ s
79
+
80
+ fun fmt indentlvl ev =
81
+ let
82
+ val check = TermColor.greenit "\226\156\148 " (* ✔ *)
83
+ val cross = TermColor.redit "\226\156\150 " (* ✖ *)
84
+ val indentlvl = indentlvl * 2
85
+ in
86
+ case ev of
87
+ Success descr => indent indentlvl (check ^ descr)
88
+ | Failure (descr, exp, got) =>
89
+ String.concatWith "\n" [indent indentlvl (cross ^ descr),
90
+ indent (indentlvl + 2) exp,
91
+ indent (indentlvl + 2) got]
92
+ | Error (descr, reason) =>
93
+ String.concatWith "\n" [indent indentlvl (cross ^ descr),
94
+ indent (indentlvl + 2) (TermColor.redit reason)]
95
+ end
96
+
97
+ fun eval (TestGroup _) = raise Fail "Only a 'Test' can be evaluated"
98
+ | eval (Test (descr, thunk)) =
99
+ (
100
+ case thunk () of
101
+ Expect.Pass => ((1, 0, 0), Success descr)
102
+ | Expect.Fail (s, s') => ((0, 1, 0), Failure (descr, s, s'))
103
+ )
104
+ handle e => ((0, 0, 1), Error (descr, "Unexpected error: " ^ exnMessage e))
105
+
106
+ fun flatten depth testnode =
107
+ let
108
+ fun sum (x, y, z) (a, b, c) = (x + a, y + b, z + c)
109
+
110
+ fun aux (t, (counter, acc)) =
111
+ let
112
+ val (counter', texts) = flatten (depth + 1) t
113
+ in
114
+ (sum counter' counter, texts :: acc)
115
+ end
116
+ in
117
+ case testnode of
118
+ TestGroup (descr, ts) =>
119
+ let
120
+ val (counter, texts) = foldr aux ((0, 0, 0), []) ts
121
+ in
122
+ (counter, (indent (depth * 2) descr) :: List.concat texts)
123
+ end
124
+ | Test _ =>
125
+ let
126
+ val (counter, evaluation) = eval testnode
127
+ in
128
+ (counter, [fmt depth evaluation])
129
+ end
130
+ end
131
+
132
+ fun println s = print (s ^ "\n")
133
+ in
134
+ fun run suite =
135
+ let
136
+ val ((succeeded, failed, errored), texts) = flatten 0 suite
137
+
138
+ val summary = String.concatWith ", " [
139
+ TermColor.greenit ((Int.toString succeeded) ^ " passed"),
140
+ TermColor.redit ((Int.toString failed) ^ " failed"),
141
+ TermColor.redit ((Int.toString errored) ^ " errored"),
142
+ (Int.toString (succeeded + failed + errored)) ^ " total"
143
+ ]
144
+
145
+ val status = if failed = 0 andalso errored = 0
146
+ then OS.Process.success
147
+ else OS.Process.failure
148
+
149
+ in
150
+ List.app println texts;
151
+ println "";
152
+ println ("Tests: " ^ summary);
153
+ OS.Process.exit status
154
+ end
155
+ end
156
+ end
157
+
158
+ fun describe description tests = Test.TestGroup (description, tests)
159
+ fun test description thunk = Test.Test (description, thunk)
@@ -0,0 +1,54 @@
1
+ # Perfect Numbers
2
+
3
+ Determine if a number is perfect, abundant, or deficient based on
4
+ Nicomachus' (60 - 120 CE) classification scheme for natural numbers.
5
+
6
+ The Greek mathematician [Nicomachus](https://en.wikipedia.org/wiki/Nicomachus) devised a classification scheme for natural numbers, identifying each as belonging uniquely to the categories of **perfect**, **abundant**, or **deficient** based on their [aliquot sum](https://en.wikipedia.org/wiki/Aliquot_sum). The aliquot sum is defined as the sum of the factors of a number not including the number itself. For example, the aliquot sum of 15 is (1 + 3 + 5) = 9
7
+
8
+ - **Perfect**: aliquot sum = number
9
+ - 6 is a perfect number because (1 + 2 + 3) = 6
10
+ - 28 is a perfect number because (1 + 2 + 4 + 7 + 14) = 28
11
+ - **Abundant**: aliquot sum > number
12
+ - 12 is an abundant number because (1 + 2 + 3 + 4 + 6) = 16
13
+ - 24 is an abundant number because (1 + 2 + 3 + 4 + 6 + 8 + 12) = 36
14
+ - **Deficient**: aliquot sum < number
15
+ - 8 is a deficient number because (1 + 2 + 4) = 7
16
+ - Prime numbers are deficient
17
+
18
+ Implement the `classify` function, it should return one of `Abundant`, `Deficient` or `Perfect`. If the input param is not a positive integer, raise the exception `NotAPositiveInteger`.
19
+
20
+ ## Loading your exercise implementation in PolyML
21
+
22
+ ```
23
+ $ poly --use {exercise}.sml
24
+ ```
25
+
26
+ Or:
27
+
28
+ ```
29
+ $ poly
30
+ > use "{exercise}.sml";
31
+ ```
32
+
33
+ **Note:** You have to replace {exercise}.
34
+
35
+ ## Running the tests
36
+
37
+ ```
38
+ $ poly -q --use test.sml
39
+ ```
40
+
41
+ ## Feedback, Issues, Pull Requests
42
+
43
+ The [exercism/sml](https://github.com/exercism/sml) repository on
44
+ GitHub is the home for all of the Standard ML exercises.
45
+
46
+ If you have feedback about an exercise, or want to help implementing a new
47
+ one, head over there and create an issue. We'll do our best to help you!
48
+
49
+ ## Source
50
+
51
+ Taken from Chapter 2 of Functional Thinking by Neal Ford. [http://shop.oreilly.com/product/0636920029687.do](http://shop.oreilly.com/product/0636920029687.do)
52
+
53
+ ## Submitting Incomplete Solutions
54
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,26 @@
1
+ exception NotAPositiveInteger
2
+
3
+ datatype classification = Abundant | Deficient | Perfect
4
+
5
+ fun sigma n =
6
+ let
7
+ fun loop i =
8
+ if i * i > n
9
+ then 0
10
+ else if n mod i <> 0
11
+ then loop (i + 1)
12
+ else if n div i = i
13
+ then i + loop (i + 1)
14
+ else i + (n div i) + loop (i + 1)
15
+ in
16
+ loop 1
17
+ end
18
+
19
+ fun classify n =
20
+ if n < 1
21
+ then raise NotAPositiveInteger
22
+ else
23
+ case Int.compare (sigma n, 2 * n) of
24
+ GREATER => Abundant
25
+ | LESS => Deficient
26
+ | _ => Perfect
@@ -0,0 +1,6 @@
1
+ exception NotAPositiveInteger
2
+
3
+ datatype classification = Abundant | Deficient | Perfect
4
+
5
+ fun classify (input: int): classification =
6
+ raise Fail "'classify' is not implemented"
@@ -0,0 +1,59 @@
1
+ (* version 1.0.1 *)
2
+
3
+ use "perfect-numbers.sml";
4
+ use "testlib.sml";
5
+
6
+ infixr |>
7
+ fun x |> f = f x
8
+
9
+ val testsuite =
10
+ describe "perfect-numbers" [
11
+ describe "Perfect numbers" [
12
+ test "Smallest perfect number is classified correctly"
13
+ (fn _ => classify (6) |> Expect.equalTo Perfect),
14
+
15
+ test "Medium perfect number is classified correctly"
16
+ (fn _ => classify (28) |> Expect.equalTo Perfect),
17
+
18
+ test "Large perfect number is classified correctly"
19
+ (fn _ => classify (33550336) |> Expect.equalTo Perfect)
20
+ ],
21
+
22
+ describe "Abundant numbers" [
23
+ test "Smallest abundant number is classified correctly"
24
+ (fn _ => classify (12) |> Expect.equalTo Abundant),
25
+
26
+ test "Medium abundant number is classified correctly"
27
+ (fn _ => classify (30) |> Expect.equalTo Abundant),
28
+
29
+ test "Large abundant number is classified correctly"
30
+ (fn _ => classify (33550335) |> Expect.equalTo Abundant)
31
+ ],
32
+
33
+ describe "Deficient numbers" [
34
+ test "Smallest prime deficient number is classified correctly"
35
+ (fn _ => classify (2) |> Expect.equalTo Deficient),
36
+
37
+ test "Smallest non-prime deficient number is classified correctly"
38
+ (fn _ => classify (4) |> Expect.equalTo Deficient),
39
+
40
+ test "Medium deficient number is classified correctly"
41
+ (fn _ => classify (32) |> Expect.equalTo Deficient),
42
+
43
+ test "Large deficient number is classified correctly"
44
+ (fn _ => classify (33550337) |> Expect.equalTo Deficient),
45
+
46
+ test "Edge case (no factors other than itself) is classified correctly"
47
+ (fn _ => classify (1) |> Expect.equalTo Deficient)
48
+ ],
49
+
50
+ describe "Invalid inputs" [
51
+ test "Zero is rejected (not a natural number)"
52
+ (fn _ => (fn _ => classify (~1)) |> Expect.error NotAPositiveInteger),
53
+
54
+ test "Negative integer is rejected (not a natural number)"
55
+ (fn _ => (fn _ => classify (~1)) |> Expect.error NotAPositiveInteger)
56
+ ]
57
+ ]
58
+
59
+ val _ = Test.run testsuite