Exercism exercises in Standard ML.
Even though there are multiple Standard ML implementations, we'll stick to PolyML.
Please read INSTALLATION.md for more info.
Any type of contribution is more than welcome!
Before opening a pull request please have look into Contributors Pull Request Guide.
Usually an exercise is derived from one of the exercises in the problem-specifications repository. If you want to contribute a completely new exercise, consider opening a pull request there to make it available to all tracks.
There is a comprehensive guide on how to add an exercise to one of the exercism tracks. It is advisable that you skim over the text. You don't have to remember everything, we recall the essentials here anyway. We also provide the track-specific details here. Down below we describe tooling which helps you with the boilerplate.
Basically, adding an exercise means to do the following things.
- Register the exercise in
{{ repo-path }}/config.json
, - Use tooling to generate exercise-folder
exercises/practice/{{ slug }}/
, - Provide a solution for the exercise in
example.sml
, - Check if the linter (configlet) is satisfied.
This step needs to be done manually. You have to add a block looking like that under
exercises/practice
:
{
"exercises": {
"practice": [
{
"slug": "flatten-array", // the slug from `problem-specifications`
"name": "Flatten Array",
"uuid": "fb0a030d-33bc-4066-a30a-1b8b02cc42f1", // use `configlet uuid` to generate this
"practices": [],
"prerequisites": [],
"difficulty": 1,
"topics": []
},
// more exercises ...
],
// more stuff ...
},
// more stuff ...
}
To generate a unique uuid
just execute the following on the command line:
$ bin/fetch-configlet # to fetch the latest version of configlet
$ bin/configlet uuid # paste the output into the `uuid` field.
A folder similar to this one has to be created:
exercises/practice/flatten-array/
├── flatten-array.sml # stub-file displayed to studend on website
├── testlib.sml # copy of the test-library (track-specific)
├── test.sml # actual test-suite
├── .docs
│ ├── instructions.append.md # optional track-specific file augmenting `instructions.md`
│ └── instructions.md # contains (track-independent) description of the exercise
└── .meta
├── config.json # you may add yourself as author here
├── example.sml # solution proving that the test-suite can actually be satisfied
└── tests.toml # specifies which tests from `problem-specifications` are implemented
The easiest way to autogenerate the boilerplate is to execute configlet
sync in combination with the track specific tool
bin/generate
. The former is responsible for required files with "generic" content, and the latter
for required files with sml-specific content
$ bin/configlet sync -yu --tests include --docs --filepaths --metadata -e {{ slug }}
$ bin/generate {{ slug }}
Note on bin/generate
: You need Python 3.5+. It may fail with some exercises. Reasons:
canonical-data.json
does not exist, or type mismatch (in these situation you can use --force
option). In those cases you will have to create the files manually.
IMPORTANT: Currently the test-framework expects example.sml
to be inside .meta/
, which is
not the case right after execution of bin/generate
. As a workaround you should move the file
manually and update the path in .meta/config.json
accordingly.
The most creative part is to write a valid solution example.sml
which passes the test-suite. To
verify that your solution is valid just execute the tests like so
$ make test-{{ slug }}
Alternatively you can verify your solution by
$ # You might need `sudo` since docker is invoked:
$ bin/test {{ slug }}
Under the hood this uses docker
to run the tests in the sml-test-runner
image. This is
essentially what happens if a student submits their own solution.
Finally check if the linter is satisfied with your work
$ bin/configlet lint
You can execute tests by
$ make test # all tests
$ make test-{{ slug }} # single test
Mainstream languages usually have one or more popular test-frameworks. Standard ML is not blessed
with this convenience. Therefore the track implements its own "test-framework" lib/testlib.sml
. It
gets the job done. For technical reasons each exercise must provide its own copy of the testlib.
Any updates to lib/testlib.sml
have to be synced to all exercises by
$ make redeploy-testlib
We don't want to deal with multiple versions of testlib. Hence the redeploy script is the only way to update the testlib of any exercise.