trackler 2.2.1.19 → 2.2.1.20
Sign up to get free protection for your applications and to get access to all the features.
- 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
|