Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/check-generated-tests-in-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ jobs:
with:
submodules: true

- name: Checkout problem-specifications
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
repository: exercism/problem-specifications
path: /home/runner/work/rescript/rescript/.cache/exercism/configlet/problem-specifications

- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
Expand All @@ -32,4 +38,6 @@ jobs:
run: npm ci

- name: Check generated tests in sync
env:
XDG_CACHE_HOME: /home/runner/work/rescript/rescript/.cache
run: bin/check-generated-tests-in-sync
29 changes: 0 additions & 29 deletions .github/workflows/check-problem-specs-is-current.yml

This file was deleted.

3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

38 changes: 32 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
# How to contribute to the Exercism ReScript track

#### **Do you want to add an exercise?**
## **Do you want to add an exercise?**

- **Ensure that someone else isn't already adding it** by searching the [forum](https://forum.exercism.org/c/programming/rescript) and the repository's [issues](https://github.com/exercism/rescript/issues) and [pull requests](https://github.com/exercism/rescript/pulls).

- If nobody is yet adding the exercise, [open a conversation](https://forum.exercism.org/c/programming/rescript) and indicate you'd like to add the exercise.

- Follow the [Add a Practice Exercise docs](https://exercism.org/docs/building/tracks/practice-exercises/add).

#### **Do you want to report a bug?**
- Read the [Add a Practice Exercise docs](https://exercism.org/docs/building/tracks/practice-exercises/add).

### Adding a practice exercise

1. Fork the repo: `gh repo fork exercism/rescript`
2. Run the add script: `bin/add-practice-exercises -a <your-github-username> -d <difficulty> <exercise-slug>`
3. That script calls `bin/configlet` which installs the [exercism/problem-specifications](https://github.com/exercism/problem-specifications) repository locally:
- the location is `$XDG_CACHE_HOME/exercism/configlet/problem-specifications`, and by default XDG_CACHE_HOME is `$HOME/.cache`
4. Generate the tests:
1. Create the template for the test generator: `make add-test-template EXERCISE=<exercise-slug>`
- this creates file `test_templates/<PascalSlug>_template.res`
- populate it based on the default comments, and browsing other templates
2. Build the project: `npx rescript build`
- this will create `test_templates/<PascalSlug>_template.res.js`
3. Generate the tests: `make generate-test EXERCISE=<exercise-slug>`
- review the generated `exercises/practice/<exercise-slug>/tests/<PascalSlug>_test.res` file
5. Create the stub source and interface files (refer to other exercises)
- `exercises/practice/<exercise-slug>/src/<PascalSlug>.res` -- for each function being tested, create a binding that panics
- `exercises/practice/<exercise-slug>/src/<PascalSlug>.resi` -- define the type signature for each function
6. Write the example solution
- copy the contents of the stub files into the `.meta/` files
- populate the `.meta/<PascalsSlug>.res` with your example solution.
It doesn't have to be optimal: it exists as a proof the exercise can be solved.
7. Test with `make test-one EXERCISE=<exercise-slug>`
- Caution: if you're on a Mac, the Makefile uses GNU sed features.
- install it with homebrew: `brew install gnu-sed`
- then put it in your path earlier than the system sed: `mkdir -p ~/bin && PATH="$HOME/bin:$PATH" && cd ~/bin && ln -s /path/to/gsed sed && cd -`

## **Do you want to report a bug?**

- **Ensure the bug was not already reported** by searching the [forum](https://forum.exercism.org/c/programming/rescript).

- If you're unable to find an open conversation addressing the problem, [open a new one](https://forum.exercism.org/new-topic?category=rescript). Be sure to include a **title and clear description**, as much relevant information as possible, and (when possible) a **code sample**.

#### **Do you want to fix a bug?**
## **Do you want to fix a bug?**

- **Ensure that the bug is [reported](#do-you-want-to-report-a-bug)**.
Only start fixing the bug when there is agreement on whether (and how) it should be fixed.
Expand All @@ -26,7 +52,7 @@

- Before submitting, please read the [Contributors Pull Request Guide](https://exercism.org/docs/building/github/contributors-pull-request-guide) and [Pull Request Guide](https://exercism.org/docs/community/being-a-good-community-member/pull-requests).

#### **Do you intend to add a new feature or change an existing one?**
## **Do you intend to add a new feature or change an existing one?**

- **Ensure that the feature or change is discussed on the [forum](https://forum.exercism.org/c/programming/rescript).**
Only start adding the feature or change when there is agreement on whether (and how) it should be added or changed.
Expand Down
3 changes: 0 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@ check-exercise-files:
for file in $(FILES_TO_CHECK); do \
target="exercises/practice/$$exercise/$$file"; \
\
# Map the source template path \
if [ -f "./templates/$$file" ]; then \
source="./templates/$$file"; \
else \
source="./$$file"; \
fi; \
\
# 1. Check if the file exists \
if [ ! -f "$$target" ]; then \
echo "ERROR: Missing file $$file in $$exercise. Run make sync-exercise-files and commit the changes."; \
exit 1; \
fi; \
\
# 2. Check if the content matches (ignoring name/version) \
if [ "$$file" != ".meta/testTemplate.js" ]; then \
diff -q -I '"name":' -I '"version":' "$$source" "$$target" > /dev/null || { \
echo "ERROR: $$target does not match template $$source."; \
Expand Down
17 changes: 2 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,6 @@ Exercism exercises in ReScript.

Track exercises target [ReScript] 12.2.0 using the [ReScript Test][ReScriptTest] testing framework on [Node.js] 22+. If you're contributing to the track, you will also need [make].

### Setting up the development environment

Run the following commands from inside the project root directory to install the required tools:

```shell
npm install
git submodule update --init --recursive # add/update a local copy of the problem-specification submodule
```

To automate the creation of practice exercise tests, our track tooling consumes data from the the [problem specifications][exercism-problem-specifications-link] submodule. Because these specifications serve as the canonical source for all Exercism tracks, any upstream updates ensure our test cases remain consistent with the global exercise standard.

If you have format on save enabled for JSON files, it is recommended to disable this feature. Alternatively save JSON files with `Ctrl+K s` to save without applying formatting rules.

## Running the development environment

Open up two terminals. By running the commands below, files will compile on save and re-run the test suite.
Expand Down Expand Up @@ -52,7 +39,7 @@ Now complete the following steps:
- Ensure that the new exercise data is correctly placed in order of difficulty and then alphabetically within that difficulty rating - `config.json`
- Implement exercise test cases, detailed in the [testing](#testing) section below - `templates/Test_template.res`
- Write an example of code here that will pass all test cases. This does not need to be the finest example of how to complete this exercise, but it must pass all the test cases - `exercises/practice/<exercise-slug>/.meta/<exercise-name>.res`
- Update the example solution's interface file with the function signatures - `exercises/practice/<exercise-slug>/.meta/<exercise-name>.reso`
- Update the example solution's interface file with the function signatures - `exercises/practice/<exercise-slug>/.meta/<exercise-name>.resi`
- Create an exercise stub which returns `panic("'<function-name>' has not been implemented")` - `exercises/practice/<exercise-slug>/src/<exercise-name>.res`
- Update the exercise stub's interface file with the exposed function signatures so that the student has a reference to what names and types are used - `exercises/practice/<exercise-slug>/src/<exercise-name>.resi`

Expand All @@ -64,7 +51,7 @@ Tests are written using [rescript-test][ReScriptTest]. There is a test templatin
- `test_templates/<Exercise>_template.res` - edit this file to allow the test generator to automatically create test files. If this file does not exist, copy `templates/Test_template.res` and rename to match the aforementioned filename.
- you must write your comparator functions - https://bloodyowl.github.io/rescript-test/assertions.
- common assertions with comparator functions are located at `test_generator/Assertions.res`. Add the ones you'd like to use to the `generateTests` function's last argument, eg `TestGenerator.generateTests(slug, template, [DictEqual])`.
- edit the `template` function so that it will generate the test cases. The `case` parameter refers to a test case in `problem-specifications/exercises/<exercise-slug>/canonical-data.json`. Refer to other exercise test templates for inspiration.
- edit the `template` function so that it will generate the test cases. The `case` parameter refers to a test case in `$HOME/.cache/exercism/configlet/problem-specifications/exercises/<exercise-slug>/canonical-data.json`. Refer to other exercise test templates for inspiration.

Run all exercise tests:

Expand Down
2 changes: 1 addition & 1 deletion bin/add-practice-exercise
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ cat << NEXT_STEPS

Your next steps are:
- Create the test suite in $(jq -r '.test' <<< "${files}")
- The tests should be based on the canonical data at 'https://github.com/exercism/problem-specifications/blob/main/exercises/${slug}/canonical-data.json'
- The tests should be based on the canonical data at '$HOME/.cache/exercism/configlet/problem-specifications/exercises/${slug}/canonical-data.json'
- Any test cases you don't implement, mark them in 'exercises/practice/${slug}/.meta/tests.toml' with "include = false"
- Create the example solution in $(jq -r '.example' <<< "${files}")
- Verify the example solution passes the tests by running 'bin/verify-exercises ${slug}'
Expand Down
22 changes: 0 additions & 22 deletions bin/check-problem-specs-is-current

This file was deleted.

8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,14 @@
"prerequisites": [],
"difficulty": 4
},
{
"slug": "sieve",
"name": "Sieve",
"uuid": "64ed04d5-c0b2-4417-a351-58437dd0b134",
"practices": [],
"prerequisites": [],
"difficulty": 4
},
{
"slug": "word-count",
"name": "Word Count",
Expand Down
101 changes: 101 additions & 0 deletions exercises/practice/sieve/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Instructions

Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find all prime numbers less than or equal to a given number.

A prime number is a number larger than 1 that is only divisible by 1 and itself.
For example, 2, 3, 5, 7, 11, and 13 are prime numbers.
By contrast, 6 is _not_ a prime number as it not only divisible by 1 and itself, but also by 2 and 3.

To use the Sieve of Eratosthenes, first, write out all the numbers from 2 up to and including your given number.
Then, follow these steps:

1. Find the next unmarked number (skipping over marked numbers).
This is a prime number.
2. Mark all the multiples of that prime number as **not** prime.

Repeat the steps until you've gone through every number.
At the end, all the unmarked numbers are prime.

~~~~exercism/note
The Sieve of Eratosthenes marks off multiples of each prime using addition (repeatedly adding the prime) or multiplication (directly computing its multiples), rather than checking each number for divisibility.

The tests don't check that you've implemented the algorithm, only that you've come up with the correct primes.
~~~~

## Example

Let's say you're finding the primes less than or equal to 10.

- Write out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked.

```text
2 3 4 5 6 7 8 9 10
```

- 2 is unmarked and is therefore a prime.
Mark 4, 6, 8 and 10 as "not prime".

```text
2 3 [4] 5 [6] 7 [8] 9 [10]
↑
```

- 3 is unmarked and is therefore a prime.
Mark 6 and 9 as not prime _(marking 6 is optional - as it's already been marked)_.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 4 is marked as "not prime", so we skip over it.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 5 is unmarked and is therefore a prime.
Mark 10 as not prime _(optional - as it's already been marked)_.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 6 is marked as "not prime", so we skip over it.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 7 is unmarked and is therefore a prime.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 8 is marked as "not prime", so we skip over it.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 9 is marked as "not prime", so we skip over it.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

- 10 is marked as "not prime", so we stop as there are no more numbers to check.

```text
2 3 [4] 5 [6] 7 [8] [9] [10]
↑
```

You've examined all the numbers and found that 2, 3, 5, and 7 are still unmarked, meaning they're the primes less than or equal to 10.
7 changes: 7 additions & 0 deletions exercises/practice/sieve/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Introduction

You bought a big box of random computer parts at a garage sale.
You've started putting the parts together to build custom computers.

You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare.
You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits.
3 changes: 3 additions & 0 deletions exercises/practice/sieve/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
**/*.res.js
lib
20 changes: 20 additions & 0 deletions exercises/practice/sieve/.meta/Sieve.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
let primes = limit => {
let flags = Array.fromInitializer(~length=limit + 1, _ => true)
flags->Array.set(0, false)
flags->Array.set(1, false)

for i in 2 to limit->Float.fromInt->Math.sqrt->Int.fromFloat {
if flags->Array.getUnsafe(i) {
let j = ref(i * i)
while j.contents <= limit {
flags->Array.set(j.contents, false)
j := j.contents + i
}
}
}

flags
->Array.mapWithIndex((isPrime, i) => (isPrime, i))
->Array.filter(((isPrime, _)) => isPrime)
->Array.map(((_, i)) => i)
}
1 change: 1 addition & 0 deletions exercises/practice/sieve/.meta/Sieve.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let primes: int => array<int>
21 changes: 21 additions & 0 deletions exercises/practice/sieve/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"authors": [
"glennj"
],
"files": {
"solution": [
"src/Sieve.res",
"src/Sieve.resi"
],
"test": [
"tests/Sieve_test.res"
],
"example": [
".meta/Sieve.res",
".meta/Sieve.resi"
]
},
"blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.",
"source": "Sieve of Eratosthenes at Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"
}
Loading
Loading