trackler 2.2.1.19 → 2.2.1.20
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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/bash/config.json +11 -0
- data/tracks/bash/docs/ABOUT.md +5 -0
- data/tracks/bash/exercises/word-count/README.md +24 -0
- data/tracks/bash/exercises/word-count/example.awk +12 -0
- data/tracks/bash/exercises/word-count/example.sh +21 -0
- data/tracks/bash/exercises/word-count/word_count_test.sh +84 -0
- data/tracks/coffeescript/config/maintainers.json +5 -11
- data/tracks/csharp/.travis.yml +3 -0
- data/tracks/delphi/config/maintainers.json +1 -1
- data/tracks/ecmascript/config.json +108 -108
- data/tracks/elixir/exercises/phone-number/phone_number_test.exs +21 -1
- data/tracks/factor/docs/SNIPPET.txt +5 -0
- data/tracks/idris/docs/TESTS.md +7 -0
- data/tracks/java/config.json +47 -47
- data/tracks/javascript/config.json +103 -103
- data/tracks/julia/config.json +121 -121
- data/tracks/julia/docs/RESOURCES.md +1 -1
- data/tracks/julia/docs/SNIPPET.txt +8 -0
- data/tracks/objective-c/config.json +2 -3
- data/tracks/objective-c/exercises/rna-transcription/RNATranscriptionExample.m +11 -32
- data/tracks/ocaml/.travis-ci.sh +1 -1
- data/tracks/ocaml/.travis.yml +1 -1
- data/tracks/ocaml/README.md +1 -1
- data/tracks/ocaml/exercises/change/test.ml +24 -21
- data/tracks/ocaml/tools/test-generator/src/codegen.ml +3 -7
- data/tracks/ocaml/tools/test-generator/src/controller.ml +4 -5
- data/tracks/ocaml/tools/test-generator/src/languages.ml +4 -3
- data/tracks/ocaml/tools/test-generator/src/model.ml +1 -2
- data/tracks/ocaml/tools/test-generator/src/ocaml_special_cases.ml +19 -18
- data/tracks/ocaml/tools/test-generator/src/parser.ml +12 -17
- data/tracks/ocaml/tools/test-generator/src/purescript_special_cases.ml +11 -3
- data/tracks/ocaml/tools/test-generator/test/codegen_test.ml +2 -3
- data/tracks/ocaml/tools/test-generator/test/ocaml_special_cases_test.ml +12 -4
- data/tracks/ocaml/tools/test-generator/test/parser_test.ml +10 -10
- data/tracks/purescript/exercises/bob/test/Main.purs +5 -5
- data/tracks/ruby/bin/generate +1 -1
- data/tracks/ruby/docs/24pullrequests.md +1 -1
- data/tracks/ruby/exercises/all-your-base/all_your_base_test.rb +24 -24
- data/tracks/ruby/exercises/alphametics/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/bowling/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/bowling/bowling_test.rb +10 -10
- data/tracks/ruby/exercises/change/.meta/.version +1 -1
- data/tracks/ruby/exercises/change/.meta/solutions/change.rb +1 -1
- data/tracks/ruby/exercises/change/change_test.rb +7 -2
- data/tracks/ruby/exercises/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb +1 -1
- data/tracks/ruby/exercises/connect/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/dominoes/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/hamming/.meta/generator/hamming_case.rb +5 -1
- data/tracks/ruby/exercises/hamming/hamming_test.rb +7 -7
- data/tracks/ruby/exercises/leap/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/exercises/pangram/.meta/.version +1 -1
- data/tracks/ruby/exercises/pangram/.meta/solutions/pangram.rb +1 -1
- data/tracks/ruby/exercises/pangram/pangram_test.rb +3 -3
- data/tracks/ruby/exercises/rna-transcription/rna_transcription_test.rb +4 -4
- data/tracks/ruby/exercises/roman-numerals/.meta/solutions/roman_numerals.rb +1 -1
- data/tracks/ruby/exercises/space-age/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/lib/generator/test_template.erb +1 -1
- data/tracks/ruby/lib/generator/underscore.rb +1 -1
- data/tracks/ruby/lib/helper.rb +4 -4
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha-beta/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/.version +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/generator/alpha_case.rb +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/generator/test_template.erb +1 -1
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/alpha/.meta/solutions/alpha.rb +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/beta/.meta/.version +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/exercises/beta/.meta/generator/beta_case.rb +0 -0
- data/tracks/ruby/test/fixtures/{xruby → ruby}/lib/generator/test_template.erb +1 -1
- data/tracks/ruby/test/generator/files/track_files_test.rb +4 -4
- data/tracks/ruby/test/generator/implementation_test.rb +1 -1
- data/tracks/ruby/test/generator/template_values_test.rb +1 -1
- data/tracks/scala/exercises/rail-fence-cipher/src/main/scala/{RailFenceCipher.scala → .keep} +0 -0
- data/tracks/scala/exercises/rail-fence-cipher/src/test/scala/RailFenceCipherTest.scala +16 -23
- data/tracks/scala/exercises/say/src/test/scala/SayTest.scala +20 -33
- data/tracks/scala/testgen/src/main/scala/RailFenceCipherTestGenerator.scala +9 -53
- data/tracks/scala/testgen/src/main/scala/SayTestGenerator.scala +50 -0
- data/tracks/sml/bin/generate +1 -1
- data/tracks/sml/config.json +30 -0
- data/tracks/sml/exercises/all-your-base/README.md +61 -0
- data/tracks/sml/exercises/all-your-base/all-your-base.sml +2 -0
- data/tracks/sml/exercises/all-your-base/example.sml +36 -0
- data/tracks/sml/exercises/all-your-base/test.sml +75 -0
- data/tracks/sml/exercises/all-your-base/testlib.sml +159 -0
- data/tracks/sml/exercises/difference-of-squares/example.sml +3 -6
- data/tracks/sml/exercises/list-ops/README.md +40 -0
- data/tracks/sml/exercises/list-ops/example.sml +34 -0
- data/tracks/sml/exercises/list-ops/list-ops.sml +23 -0
- data/tracks/sml/exercises/list-ops/test.sml +85 -0
- data/tracks/sml/exercises/list-ops/testlib.sml +159 -0
- data/tracks/sml/exercises/prime-factors/README.md +66 -0
- data/tracks/sml/exercises/prime-factors/example.sml +15 -0
- data/tracks/sml/exercises/prime-factors/prime-factors.sml +2 -0
- data/tracks/sml/exercises/prime-factors/test.sml +35 -0
- data/tracks/sml/exercises/prime-factors/testlib.sml +159 -0
- metadata +34 -11
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# List Ops
|
|
2
|
+
|
|
3
|
+
Implement basic list operations.
|
|
4
|
+
|
|
5
|
+
In functional languages list operations like `length`, `map`, and
|
|
6
|
+
`reduce` are very common. Implement a series of basic list operations,
|
|
7
|
+
without using existing functions.
|
|
8
|
+
|
|
9
|
+
## Loading your exercise implementation in PolyML
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
$ poly --use {exercise}.sml
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
$ poly
|
|
19
|
+
> use "{exercise}.sml";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Note:** You have to replace {exercise}.
|
|
23
|
+
|
|
24
|
+
## Running the tests
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
$ poly -q --use test.sml
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Feedback, Issues, Pull Requests
|
|
31
|
+
|
|
32
|
+
The [exercism/sml](https://github.com/exercism/sml) repository on
|
|
33
|
+
GitHub is the home for all of the Standard ML exercises.
|
|
34
|
+
|
|
35
|
+
If you have feedback about an exercise, or want to help implementing a new
|
|
36
|
+
one, head over there and create an issue. We'll do our best to help you!
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## Submitting Incomplete Solutions
|
|
40
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
fun concat [] = []
|
|
2
|
+
| concat [[]] = []
|
|
3
|
+
| concat ([] :: xss) = concat xss
|
|
4
|
+
| concat ((x :: xs) :: xss) = x :: concat (xs :: xss)
|
|
5
|
+
|
|
6
|
+
fun reverse xs =
|
|
7
|
+
let
|
|
8
|
+
fun reverse' acc [] = acc
|
|
9
|
+
| reverse' acc (x :: xs) = reverse' (x :: acc) xs
|
|
10
|
+
in
|
|
11
|
+
reverse' [] xs
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
fun filter (predicate, []) = []
|
|
15
|
+
| filter (predicate, (x :: xs)) =
|
|
16
|
+
if predicate x
|
|
17
|
+
then x :: filter (predicate, xs)
|
|
18
|
+
else filter (predicate, xs)
|
|
19
|
+
|
|
20
|
+
fun map (f, []) = []
|
|
21
|
+
| map (f, x :: xs) = f x :: map (f, xs)
|
|
22
|
+
|
|
23
|
+
fun append (xs, []) = xs
|
|
24
|
+
| append ([], ys) = ys
|
|
25
|
+
| append (x :: xs, ys) = x :: append(xs, ys)
|
|
26
|
+
|
|
27
|
+
fun length [] = 0
|
|
28
|
+
| length (x :: xs) = 1 + length xs
|
|
29
|
+
|
|
30
|
+
fun foldl (_, acc, []) = acc
|
|
31
|
+
| foldl (f, acc, (x :: xs)) = foldl (f, (f (acc, x)), xs)
|
|
32
|
+
|
|
33
|
+
fun foldr (f, acc, []) = acc
|
|
34
|
+
| foldr (f, acc, (x::xs)) = f (x, (foldr (f, acc, xs)))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
fun concat (lists: int list list): int list =
|
|
2
|
+
raise Fail "'concat' is not implemented"
|
|
3
|
+
|
|
4
|
+
fun reverse (list: int list): int list =
|
|
5
|
+
raise Fail "'reverse' is not implemented"
|
|
6
|
+
|
|
7
|
+
fun filter (function: int -> bool, list: int list): int list =
|
|
8
|
+
raise Fail "'filter' is not implemented"
|
|
9
|
+
|
|
10
|
+
fun map (function: int -> int, list: int list): int list =
|
|
11
|
+
raise Fail "'map' is not implemented"
|
|
12
|
+
|
|
13
|
+
fun append (list1: int list, list2: int list): int list =
|
|
14
|
+
raise Fail "'append' is not implemented"
|
|
15
|
+
|
|
16
|
+
fun length (ns: int list): int =
|
|
17
|
+
raise Fail "'length' is not implemented"
|
|
18
|
+
|
|
19
|
+
fun foldl (function: int * int -> int, initial: int, list: int list): int =
|
|
20
|
+
raise Fail "'foldl' is not implemented"
|
|
21
|
+
|
|
22
|
+
fun foldr (function: int * int -> int, initial: int, list: int list): int =
|
|
23
|
+
raise Fail "'foldr' is not implemented"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
(* version 2.0.0 *)
|
|
2
|
+
|
|
3
|
+
use "testlib.sml";
|
|
4
|
+
use "list-ops.sml";
|
|
5
|
+
|
|
6
|
+
infixr |>
|
|
7
|
+
fun x |> f = f x
|
|
8
|
+
|
|
9
|
+
val testsuite =
|
|
10
|
+
describe "list-ops" [
|
|
11
|
+
describe "append entries to a list and return the new list" [
|
|
12
|
+
test "empty lists"
|
|
13
|
+
(fn _ => append ([], []) |> Expect.equalTo []),
|
|
14
|
+
|
|
15
|
+
test "empty list to list"
|
|
16
|
+
(fn _ => append ([], [1, 2, 3, 4]) |> Expect.equalTo [1, 2, 3, 4]),
|
|
17
|
+
|
|
18
|
+
test "non-empty lists"
|
|
19
|
+
(fn _ => append ([1, 2], [2, 3, 4, 5]) |> Expect.equalTo [1, 2, 2, 3, 4, 5])
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
describe "concat lists and lists of list into a new list" [
|
|
23
|
+
test "empty list"
|
|
24
|
+
(fn _ => concat ([]) |> Expect.equalTo []),
|
|
25
|
+
|
|
26
|
+
test "list of lists"
|
|
27
|
+
(fn _ => concat ([[1, 2], [3], [], [4, 5, 6]]) |> Expect.equalTo [1, 2, 3, 4, 5, 6])
|
|
28
|
+
],
|
|
29
|
+
|
|
30
|
+
describe "filter list returning only values that satisfy the filter function" [
|
|
31
|
+
test "empty list"
|
|
32
|
+
(fn _ => filter (fn n => n mod 2 = 1, []) |> Expect.equalTo []),
|
|
33
|
+
|
|
34
|
+
test "non-empty list"
|
|
35
|
+
(fn _ => filter (fn n => n mod 2 = 1, [1, 2, 3, 5]) |> Expect.equalTo [1, 3, 5])
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
describe "returns the length of a list" [
|
|
39
|
+
test "empty list"
|
|
40
|
+
(fn _ => length ([]) |> Expect.equalTo 0),
|
|
41
|
+
|
|
42
|
+
test "non-empty list"
|
|
43
|
+
(fn _ => length ([1, 2, 3, 4]) |> Expect.equalTo 4)
|
|
44
|
+
],
|
|
45
|
+
|
|
46
|
+
describe "return a list of elements whos values equal the list value transformed by the mapping function" [
|
|
47
|
+
test "empty list"
|
|
48
|
+
(fn _ => map (fn n => n + 1, []) |> Expect.equalTo []),
|
|
49
|
+
|
|
50
|
+
test "non-empty list"
|
|
51
|
+
(fn _ => map (fn n => n + 1, [1, 3, 5, 7]) |> Expect.equalTo [2, 4, 6, 8])
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
describe "folds (reduces) the given list from the left with a function" [
|
|
55
|
+
test "empty list"
|
|
56
|
+
(fn _ => foldl (fn (x, y) => x * y, 2, []) |> Expect.equalTo 2),
|
|
57
|
+
|
|
58
|
+
test "direction independent function applied to non-empty list"
|
|
59
|
+
(fn _ => foldl (fn (x, y) => x + y, 5, [1, 2, 3, 4]) |> Expect.equalTo 15),
|
|
60
|
+
|
|
61
|
+
test "direction dependent function applied to non-empty list"
|
|
62
|
+
(fn _ => foldl (fn (x, y) => x div y, 5, [2, 5]) |> Expect.equalTo 0)
|
|
63
|
+
],
|
|
64
|
+
|
|
65
|
+
describe "folds (reduces) the given list from the right with a function" [
|
|
66
|
+
test "empty list"
|
|
67
|
+
(fn _ => foldr (fn (x, y) => x * y, 2, []) |> Expect.equalTo 2),
|
|
68
|
+
|
|
69
|
+
test "direction independent function applied to non-empty list"
|
|
70
|
+
(fn _ => foldr (fn (x, y) => x + y, 5, [1, 2, 3, 4]) |> Expect.equalTo 15),
|
|
71
|
+
|
|
72
|
+
test "direction dependent function applied to non-empty list"
|
|
73
|
+
(fn _ => foldr (fn (x, y) => x div y, 5, [2, 5]) |> Expect.equalTo 2)
|
|
74
|
+
],
|
|
75
|
+
|
|
76
|
+
describe "reverse the elements of the list" [
|
|
77
|
+
test "empty list"
|
|
78
|
+
(fn _ => reverse ([]) |> Expect.equalTo []),
|
|
79
|
+
|
|
80
|
+
test "non-empty list"
|
|
81
|
+
(fn _ => reverse ([1, 3, 5, 7]) |> Expect.equalTo [7, 5, 3, 1])
|
|
82
|
+
]
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
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,66 @@
|
|
|
1
|
+
# Prime Factors
|
|
2
|
+
|
|
3
|
+
Compute the prime factors of a given natural number.
|
|
4
|
+
|
|
5
|
+
A prime number is only evenly divisible by itself and 1.
|
|
6
|
+
|
|
7
|
+
Note that 1 is not a prime number.
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
What are the prime factors of 60?
|
|
12
|
+
|
|
13
|
+
- Our first divisor is 2. 2 goes into 60, leaving 30.
|
|
14
|
+
- 2 goes into 30, leaving 15.
|
|
15
|
+
- 2 doesn't go cleanly into 15. So let's move on to our next divisor, 3.
|
|
16
|
+
- 3 goes cleanly into 15, leaving 5.
|
|
17
|
+
- 3 does not go cleanly into 5. The next possible factor is 4.
|
|
18
|
+
- 4 does not go cleanly into 5. The next possible factor is 5.
|
|
19
|
+
- 5 does go cleanly into 5.
|
|
20
|
+
- We're left only with 1, so now, we're done.
|
|
21
|
+
|
|
22
|
+
Our successful divisors in that computation represent the list of prime
|
|
23
|
+
factors of 60: 2, 2, 3, and 5.
|
|
24
|
+
|
|
25
|
+
You can check this yourself:
|
|
26
|
+
|
|
27
|
+
- 2 * 2 * 3 * 5
|
|
28
|
+
- = 4 * 15
|
|
29
|
+
- = 60
|
|
30
|
+
- Success!
|
|
31
|
+
|
|
32
|
+
## Loading your exercise implementation in PolyML
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
$ poly --use {exercise}.sml
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
$ poly
|
|
42
|
+
> use "{exercise}.sml";
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Note:** You have to replace {exercise}.
|
|
46
|
+
|
|
47
|
+
## Running the tests
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
$ poly -q --use test.sml
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Feedback, Issues, Pull Requests
|
|
54
|
+
|
|
55
|
+
The [exercism/sml](https://github.com/exercism/sml) repository on
|
|
56
|
+
GitHub is the home for all of the Standard ML exercises.
|
|
57
|
+
|
|
58
|
+
If you have feedback about an exercise, or want to help implementing a new
|
|
59
|
+
one, head over there and create an issue. We'll do our best to help you!
|
|
60
|
+
|
|
61
|
+
## Source
|
|
62
|
+
|
|
63
|
+
The Prime Factors Kata by Uncle Bob [http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata](http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata)
|
|
64
|
+
|
|
65
|
+
## Submitting Incomplete Solutions
|
|
66
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
fun factors n =
|
|
2
|
+
let
|
|
3
|
+
fun aux prime n =
|
|
4
|
+
if prime * prime > n
|
|
5
|
+
then [n]
|
|
6
|
+
else if n mod prime = 0
|
|
7
|
+
then prime :: aux prime (n div prime)
|
|
8
|
+
else if prime = 2
|
|
9
|
+
then aux (prime + 1) n
|
|
10
|
+
else aux (prime + 2) n
|
|
11
|
+
in
|
|
12
|
+
if n < 2
|
|
13
|
+
then []
|
|
14
|
+
else aux 2 n
|
|
15
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
(* version 1.0.0 *)
|
|
2
|
+
|
|
3
|
+
use "prime-factors.sml";
|
|
4
|
+
use "testlib.sml";
|
|
5
|
+
|
|
6
|
+
infixr |>
|
|
7
|
+
fun x |> f = f x
|
|
8
|
+
|
|
9
|
+
val testsuite =
|
|
10
|
+
describe "prime-factors" [
|
|
11
|
+
describe "returns prime factors for the given input number" [
|
|
12
|
+
test "no factors"
|
|
13
|
+
(fn _ => factors (1) |> Expect.equalTo []),
|
|
14
|
+
|
|
15
|
+
test "prime number"
|
|
16
|
+
(fn _ => factors (2) |> Expect.equalTo [2]),
|
|
17
|
+
|
|
18
|
+
test "square of a prime"
|
|
19
|
+
(fn _ => factors (9) |> Expect.equalTo [3, 3]),
|
|
20
|
+
|
|
21
|
+
test "cube of a prime"
|
|
22
|
+
(fn _ => factors (8) |> Expect.equalTo [2, 2, 2]),
|
|
23
|
+
|
|
24
|
+
test "product of primes and non-primes"
|
|
25
|
+
(fn _ => factors (12) |> Expect.equalTo [2, 2, 3]),
|
|
26
|
+
|
|
27
|
+
test "product of primes"
|
|
28
|
+
(fn _ => factors (901255) |> Expect.equalTo [5, 17, 23, 461]),
|
|
29
|
+
|
|
30
|
+
test "factors include a large prime"
|
|
31
|
+
(fn _ => factors (93819012551) |> Expect.equalTo [11, 9539, 894119])
|
|
32
|
+
]
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
val _ = Test.run testsuite
|