├── .appends └── .github │ └── labels.yml ├── .github ├── CODEOWNERS ├── dependabot.yml ├── labels.yml ├── stale.yml └── workflows │ ├── ci.yml │ ├── configlet.yml │ ├── no-important-files-changed.yml │ ├── ping-cross-track-maintainers-team.yml │ └── sync-labels.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Makefile ├── README.md ├── bin ├── add-practice-exercise ├── fetch-configlet ├── generate └── test ├── config.json ├── docs ├── ABOUT.md ├── INSTALLATION.md ├── LEARNING.md ├── RESOURCES.md ├── SNIPPET.txt ├── TESTS.md └── config.json ├── exercises ├── practice │ ├── accumulate │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── accumulate.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── acronym │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── acronym.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── affine-cipher │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── affine-cipher.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── all-your-base │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── all-your-base.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── allergies │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── allergies.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── anagram │ │ ├── .docs │ │ │ ├── instructions.append.md │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── anagram.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── armstrong-numbers │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── armstrong-numbers.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── atbash-cipher │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── atbash-cipher.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── binary-search │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── binary-search.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── binary │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── binary.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── bob │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── description.md │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── bob.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── book-store │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── book-store.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── bottle-song │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── bottle-song.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── circular-buffer │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── circular-buffer.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── collatz-conjecture │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── collatz-conjecture.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── darts │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── darts.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── diamond │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── diamond.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── difference-of-squares │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── difference-of-squares.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── eliuds-eggs │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── eliuds-eggs.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── flatten-array │ │ ├── .docs │ │ │ ├── instructions.append.md │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── flatten-array.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── food-chain │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── food-chain.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── gigasecond │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── gigasecond.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── grains │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── grains.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── hamming │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── hamming.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── hello-world │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── hello-world.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── house │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── house.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── isbn-verifier │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── isbn-verifier.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── isogram │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── isogram.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── kindergarten-garden │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── kindergarten-garden.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── knapsack │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── knapsack.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── largest-series-product │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── largest-series-product.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── leap │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── leap.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── list-ops │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── list-ops.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── luhn │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── luhn.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── matching-brackets │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── matching-brackets.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── matrix │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── matrix.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── nth-prime │ │ ├── .docs │ │ │ ├── instructions.append.md │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── nth-prime.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── nucleotide-count │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── nucleotide-count.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── palindrome-products │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── palindrome-products.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── pangram │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── pangram.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── pascals-triangle │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── pascals-triangle.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── perfect-numbers │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── perfect-numbers.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── phone-number │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── phone-number.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── pig-latin │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── pig-latin.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── prime-factors │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── prime-factors.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── protein-translation │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── protein-translation.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── proverb │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── proverb.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── pythagorean-triplet │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── pythagorean-triplet.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── queen-attack │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── queen-attack.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── raindrops │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── raindrops.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── resistor-color-duo │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── resistor-color-duo.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── resistor-color │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── resistor-color.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── reverse-string │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── reverse-string.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── rna-transcription │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── rna-transcription.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── roman-numerals │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── roman-numerals.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── rotational-cipher │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── rotational-cipher.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── run-length-encoding │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── run-length-encoding.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── say │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── say.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── scrabble-score │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── scrabble-score.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── secret-handshake │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── secret-handshake.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── sieve │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── sieve.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── space-age │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── space-age.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── square-root │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── square-root.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── strain │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── strain.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── sublist │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── sublist.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── sum-of-multiples │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── sum-of-multiples.sml │ │ ├── test.sml │ │ └── testlib.sml │ ├── transpose │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── test.sml │ │ ├── testlib.sml │ │ └── transpose.sml │ ├── triangle │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── test.sml │ │ ├── testlib.sml │ │ └── triangle.sml │ ├── twelve-days │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── test.sml │ │ ├── testlib.sml │ │ └── twelve-days.sml │ ├── two-fer │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── test.sml │ │ ├── testlib.sml │ │ └── two-fer.sml │ ├── wordy │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.sml │ │ │ └── tests.toml │ │ ├── test.sml │ │ ├── testlib.sml │ │ └── wordy.sml │ └── yacht │ │ ├── .docs │ │ ├── instructions.md │ │ └── introduction.md │ │ ├── .meta │ │ ├── config.json │ │ ├── example.sml │ │ └── tests.toml │ │ ├── test.sml │ │ ├── testlib.sml │ │ └── yacht.sml └── shared │ └── .docs │ ├── help.md │ └── tests.md ├── lib └── testlib.sml └── scripts ├── redeploy-testlib.sml └── test-in-docker.sh /.appends/.github/labels.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------------------- # 2 | # These are the repository-specific labels that augment the Exercise-wide labels defined in # 3 | # https://github.com/exercism/org-wide-files/blob/main/global-files/.github/labels.yml. # 4 | # ----------------------------------------------------------------------------------------- # 5 | 6 | - name: "Hacktoberfest" 7 | description: "" 8 | color: "5319e7" 9 | 10 | - name: "bug" 11 | description: "" 12 | color: "fc2929" 13 | 14 | - name: "duplicate" 15 | description: "" 16 | color: "cccccc" 17 | 18 | - name: "enhancement" 19 | description: "" 20 | color: "84b6eb" 21 | 22 | - name: "first-timers only" 23 | description: "" 24 | color: "159818" 25 | 26 | - name: "good first patch" 27 | description: "" 28 | color: "009248" 29 | 30 | - name: "invalid" 31 | description: "" 32 | color: "e6e6e6" 33 | 34 | - name: "pinned" 35 | description: "" 36 | color: "cccccc" 37 | 38 | - name: "question" 39 | description: "" 40 | color: "cc317c" 41 | 42 | - name: "stale" 43 | description: "" 44 | color: "bfdadc" 45 | 46 | - name: "wip" 47 | description: "" 48 | color: "c2e0c6" 49 | 50 | - name: "wontfix" 51 | description: "" 52 | color: "ffffff" 53 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Code owners 2 | .github/CODEOWNERS @exercism/maintainers-admin 3 | 4 | # Changes to `fetch-configlet` should be made in the `exercism/configlet` repo 5 | bin/fetch-configlet @exercism/maintainers-admin 6 | 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | 5 | # Keep dependencies for GitHub Actions up-to-date 6 | - package-ecosystem: 'github-actions' 7 | directory: '/' 8 | schedule: 9 | interval: 'monthly' 10 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an Issue or Pull Request becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale Issue or Pull Request is closed 4 | daysUntilClose: 7 5 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking as stale 10 | staleLabel: stale 11 | # Comment to post when marking as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when removing the stale label. Set to `false` to disable 17 | unmarkComment: false 18 | # Comment to post when closing a stale Issue or Pull Request. Set to `false` to disable 19 | closeComment: false 20 | # Limit to only `issues` or `pulls` 21 | # only: issues 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: sml / ci 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | workflow_dispatch: 8 | 9 | jobs: 10 | ci: 11 | runs-on: ubuntu-22.04 12 | 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 16 | - run: docker pull exercism/sml-test-runner 17 | - name: Run tests for all exercises 18 | run: sh ./bin/test 19 | -------------------------------------------------------------------------------- /.github/workflows/configlet.yml: -------------------------------------------------------------------------------- 1 | name: Configlet 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | configlet: 15 | uses: exercism/github-actions/.github/workflows/configlet.yml@main 16 | -------------------------------------------------------------------------------- /.github/workflows/no-important-files-changed.yml: -------------------------------------------------------------------------------- 1 | name: No important files changed 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened] 6 | branches: [main] 7 | paths: 8 | - "exercises/concept/**" 9 | - "exercises/practice/**" 10 | - "!exercises/*/*/.approaches/**" 11 | - "!exercises/*/*/.articles/**" 12 | - "!exercises/*/*/.docs/**" 13 | - "!exercises/*/*/.meta/**" 14 | 15 | permissions: 16 | pull-requests: write 17 | 18 | jobs: 19 | check: 20 | uses: exercism/github-actions/.github/workflows/check-no-important-files-changed.yml@main 21 | with: 22 | repository: ${{ github.event.pull_request.head.repo.owner.login }}/${{ github.event.pull_request.head.repo.name }} 23 | ref: ${{ github.head_ref }} 24 | -------------------------------------------------------------------------------- /.github/workflows/ping-cross-track-maintainers-team.yml: -------------------------------------------------------------------------------- 1 | name: Ping cross-track maintainers team 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | 8 | permissions: 9 | pull-requests: write 10 | 11 | jobs: 12 | ping: 13 | if: github.repository_owner == 'exercism' # Stops this job from running on forks 14 | uses: exercism/github-actions/.github/workflows/ping-cross-track-maintainers-team.yml@main 15 | secrets: 16 | github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} 17 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yml: -------------------------------------------------------------------------------- 1 | name: Tools 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/labels.yml 9 | - .github/workflows/sync-labels.yml 10 | workflow_dispatch: 11 | schedule: 12 | - cron: 0 0 1 * * # First day of each month 13 | 14 | permissions: 15 | issues: write 16 | 17 | jobs: 18 | sync-labels: 19 | uses: exercism/github-actions/.github/workflows/labels.yml@main 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/configlet 2 | bin/configlet.exe 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Exercism 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dirs := $(wildcard exercises/practice/*) 2 | all-tests := $(addprefix test-, $(notdir $(dirs))) 3 | 4 | test: $(all-tests) 5 | 6 | test-%: 7 | $(eval exercise := $(patsubst test-%, %, $@)) 8 | @echo 9 | @ls ./exercises/practice/$(exercise)/.docs/instructions.md > /dev/null 10 | @# check stub type 11 | @cd ./exercises/practice/$(exercise) && \ 12 | poly -q --use test | grep 'error: Type error' | \ 13 | wc -l | xargs -I @ expr @ = 0 > /dev/null || \ 14 | { echo '$(exercise).sml is faulty'; exit 1; } 15 | @cd ./exercises/practice/$(exercise) && cat test.sml | sed 's/$(exercise).sml/.meta\/example.sml/' | poly -q 16 | @echo 17 | 18 | redeploy-testlib: 19 | poly --script scripts/redeploy-testlib.sml 20 | 21 | .PHONY: test redeploy-testlib 22 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Synopsis: 4 | # Test the sml track's exercises. 5 | # 6 | # For each exercise we type-check the template solution (which is 7 | # provided to the students) and test if the example solution 8 | # .meta/example.sml passes the tests. 9 | # 10 | # Usage: 11 | # ./bin/test [slug...] 12 | 13 | all_slugs="$*" 14 | if [ -z "$all_slugs" ]; then 15 | all_slugs=$(ls ./exercises/practice/) 16 | fi 17 | 18 | docker run --rm --entrypoint bash \ 19 | --network none \ 20 | --mount type=bind,src=$(realpath ./exercises),dst=/exercises,ro \ 21 | --mount type=bind,src=$(realpath ./scripts),dst=/scripts,ro \ 22 | exercism/sml-test-runner \ 23 | /scripts/test-in-docker.sh $all_slugs 24 | 25 | exit_code=$? 26 | 27 | exit ${exit_code} 28 | -------------------------------------------------------------------------------- /docs/INSTALLATION.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | We'll be using `PolyML` as our `Standard ML` implementation. 4 | 5 | If you are using Windows you can download an installer from https://github.com/polyml/polyml/releases. General instructions for Linux/OS X/Free BSD can be found at https://github.com/polyml/polyml/blob/master/README.md. 6 | 7 | If you want to install from source, the process is pretty easy: 8 | ``` 9 | $ git clone https://github.com/polyml/polyml.git 10 | $ cd polyml 11 | $ ./configure 12 | ``` 13 | 14 | If you want to install it in a custom location for instance `$HOME/.local`: 15 | ``` 16 | $ ./configure --prefix=$HOME/.local 17 | ``` 18 | 19 | Last step: 20 | ``` 21 | $ make compiler 22 | $ make install 23 | ``` 24 | 25 | Check that it was installed correctly: 26 | ``` 27 | $ poly 28 | ``` 29 | 30 | if you see the interpreter, you are ready! if not, you'll probably have to add `$HOME/.local/bin` (or `/bin`) to your `$PATH`. 31 | -------------------------------------------------------------------------------- /docs/SNIPPET.txt: -------------------------------------------------------------------------------- 1 | fun fib 0 = 0 2 | | fib 1 = 1 3 | | fib n = fib (n - 1) + fib (n - 2) 4 | -------------------------------------------------------------------------------- /docs/TESTS.md: -------------------------------------------------------------------------------- 1 | # Running the tests 2 | 3 | ``` 4 | $ poly -q --use test.sml 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs": [ 3 | { 4 | "uuid": "c9940926-0d32-49dc-be67-3ad84f955b62", 5 | "slug": "installation", 6 | "path": "docs/INSTALLATION.md", 7 | "title": "Installing Standard ML locally", 8 | "blurb": "Learn how to install Standard ML locally to solve Exercism's exercises on your own machine" 9 | }, 10 | { 11 | "uuid": "c2d09890-f131-4abe-b1c0-b3c12f7e37bc", 12 | "slug": "learning", 13 | "path": "docs/LEARNING.md", 14 | "title": "How to learn Standard ML", 15 | "blurb": "An overview of how to get started from scratch with Standard ML" 16 | }, 17 | { 18 | "uuid": "2a2f5288-f3e1-4b09-b786-efc968e7b280", 19 | "slug": "tests", 20 | "path": "docs/TESTS.md", 21 | "title": "Testing on the Standard ML track", 22 | "blurb": "Learn how to test your Standard ML exercises on Exercism" 23 | }, 24 | { 25 | "uuid": "28ffa9a7-d8cc-4a56-b77c-6fcbaab3a5ad", 26 | "slug": "resources", 27 | "path": "docs/RESOURCES.md", 28 | "title": "Useful Standard ML resources", 29 | "blurb": "A collection of useful resources to help you master Standard ML" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /exercises/practice/accumulate/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection. 4 | 5 | Given the collection of numbers: 6 | 7 | - 1, 2, 3, 4, 5 8 | 9 | And the operation: 10 | 11 | - square a number (`x => x * x`) 12 | 13 | Your code should be able to produce the collection of squares: 14 | 15 | - 1, 4, 9, 16, 25 16 | 17 | Check out the test suite to see the expected function signature. 18 | 19 | ## Restrictions 20 | 21 | Keep your hands off that collect/map/fmap/whatchamacallit functionality provided by your standard library! 22 | Solve this one yourself using other basic tools instead. 23 | -------------------------------------------------------------------------------- /exercises/practice/accumulate/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "hanjiexi", 5 | "iHiD", 6 | "kytrinyx", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "snahor", 10 | "sshine" 11 | ], 12 | "files": { 13 | "solution": [ 14 | "accumulate.sml" 15 | ], 16 | "test": [ 17 | "test.sml" 18 | ], 19 | "example": [ 20 | ".meta/example.sml" 21 | ] 22 | }, 23 | "blurb": "Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection.", 24 | "source": "Conversation with James Edward Gray II", 25 | "source_url": "https://twitter.com/jeg2" 26 | } 27 | -------------------------------------------------------------------------------- /exercises/practice/accumulate/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun accumulate (_, []) = [] 2 | | accumulate (f, x::xs) = f x :: accumulate (f, xs) 3 | -------------------------------------------------------------------------------- /exercises/practice/accumulate/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [64d97c14-36dd-44a8-9621-2cecebd6ed23] 13 | description = "accumulate empty" 14 | 15 | [00008ed2-4651-4929-8c08-8b4dbd70872e] 16 | description = "accumulate squares" 17 | 18 | [551016da-4396-4cae-b0ec-4c3a1a264125] 19 | description = "accumulate upcases" 20 | 21 | [cdf95597-b6ec-4eac-a838-3480d13d0d05] 22 | description = "accumulate reversed strings" 23 | 24 | [bee8e9b6-b16f-4cd2-be3b-ccf7457e50bb] 25 | description = "accumulate recursively" 26 | -------------------------------------------------------------------------------- /exercises/practice/accumulate/accumulate.sml: -------------------------------------------------------------------------------- 1 | fun accumulate (f, xs) = 2 | raise Fail "'accumulate' has not been implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/accumulate/test.sml: -------------------------------------------------------------------------------- 1 | use "accumulate.sml"; 2 | use "testlib.sml"; 3 | 4 | infixr |> 5 | fun x |> f = f x 6 | 7 | val testsuite = 8 | describe "accumulate" [ 9 | test "applying a function to the empty-list does nothing" 10 | (fn _ => accumulate (fn x => x, []) |> Expect.equalTo []), 11 | 12 | test "applying an identify function to any list returns the source list" 13 | (fn _ => accumulate (fn x => x, [1,2,3]) |> Expect.equalTo [1,2,3]), 14 | 15 | test "applying a square function to [1,2,3] produces [1,4,9]" 16 | (fn _ => accumulate (fn x => x * x, [1,2,3]) |> Expect.equalTo [1,4,9]), 17 | 18 | test "applying a cube function to [1,2,3] produces [1,8,27]" 19 | (fn _ => accumulate (fn x => x * x * x, [1,2,3]) |> Expect.equalTo [1,8,27]), 20 | 21 | test "applying an increment function to [1,2,3] produces [2,3,4]" 22 | (fn _ => accumulate (fn x => x + 1, [1,2,3]) |> Expect.equalTo [2,3,4]), 23 | 24 | test "applying an decrement function to [1,2,3] produces [0,1,2]" 25 | (fn _ => accumulate (fn x => x - 1, [1,2,3]) |> Expect.equalTo [0,1,2]) 26 | ] 27 | 28 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/acronym/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Convert a phrase to its acronym. 4 | 5 | Techies love their TLA (Three Letter Acronyms)! 6 | 7 | Help generate some jargon by writing a program that converts a long name like Portable Network Graphics to its acronym (PNG). 8 | 9 | Punctuation is handled as follows: hyphens are word separators (like whitespace); all other punctuation can be removed from the input. 10 | 11 | For example: 12 | 13 | | Input | Output | 14 | | ------------------------- | ------ | 15 | | As Soon As Possible | ASAP | 16 | | Liquid-crystal display | LCD | 17 | | Thank George It's Friday! | TGIF | 18 | -------------------------------------------------------------------------------- /exercises/practice/acronym/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "rainij" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "acronym.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Convert a long phrase to its acronym.", 17 | "source": "Julien Vanier", 18 | "source_url": "https://github.com/monkbroc" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/acronym/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun abbreviate (phrase: string): string = 2 | let 3 | fun is_delim c = Char.contains " -_," c 4 | val tokens = String.tokens is_delim phrase 5 | fun first_char_up word = Char.toUpper (String.sub (word, 0)) 6 | in 7 | String.implode (List.map first_char_up tokens) 8 | end; 9 | -------------------------------------------------------------------------------- /exercises/practice/acronym/acronym.sml: -------------------------------------------------------------------------------- 1 | fun abbreviate (phrase: string): string = 2 | raise Fail "'abbreviate' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/affine-cipher/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "rainij" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "affine-cipher.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Create an implementation of the Affine cipher, an ancient encryption algorithm from the Middle East.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Affine_cipher" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/affine-cipher/affine-cipher.sml: -------------------------------------------------------------------------------- 1 | fun encode (key: {a: int, b: int}, phrase: string): string = 2 | raise Fail "'encode' is not implemented" 3 | 4 | fun decode (key: {a: int, b: int}, phrase: string): string = 5 | raise Fail "'decode' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/all-your-base/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Convert a sequence of digits in one base, representing a number, into a sequence of digits in another base, representing the same number. 4 | 5 | ~~~~exercism/note 6 | Try to implement the conversion yourself. 7 | Do not use something else to perform the conversion for you. 8 | ~~~~ 9 | 10 | ## About [Positional Notation][positional-notation] 11 | 12 | In positional notation, a number in base **b** can be understood as a linear combination of powers of **b**. 13 | 14 | The number 42, _in base 10_, means: 15 | 16 | `(4 × 10¹) + (2 × 10⁰)` 17 | 18 | The number 101010, _in base 2_, means: 19 | 20 | `(1 × 2⁵) + (0 × 2⁴) + (1 × 2³) + (0 × 2²) + (1 × 2¹) + (0 × 2⁰)` 21 | 22 | The number 1120, _in base 3_, means: 23 | 24 | `(1 × 3³) + (1 × 3²) + (2 × 3¹) + (0 × 3⁰)` 25 | 26 | _Yes. Those three numbers above are exactly the same. Congratulations!_ 27 | 28 | [positional-notation]: https://en.wikipedia.org/wiki/Positional_notation 29 | -------------------------------------------------------------------------------- /exercises/practice/all-your-base/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You've just been hired as professor of mathematics. 4 | Your first week went well, but something is off in your second week. 5 | The problem is that every answer given by your students is wrong! 6 | Luckily, your math skills have allowed you to identify the problem: the student answers _are_ correct, but they're all in base 2 (binary)! 7 | Amazingly, it turns out that each week, the students use a different base. 8 | To help you quickly verify the student answers, you'll be building a tool to translate between bases. 9 | -------------------------------------------------------------------------------- /exercises/practice/all-your-base/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "iHiD", 5 | "mcmillhj-wta", 6 | "sjwarner-bp", 7 | "sshine" 8 | ], 9 | "files": { 10 | "solution": [ 11 | "all-your-base.sml" 12 | ], 13 | "test": [ 14 | "test.sml" 15 | ], 16 | "example": [ 17 | ".meta/example.sml" 18 | ] 19 | }, 20 | "blurb": "Convert a number, represented as a sequence of digits in one base, to any other base." 21 | } 22 | -------------------------------------------------------------------------------- /exercises/practice/all-your-base/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun rebase (inBase, outBase, digits) = let 2 | fun fromBase base = let 3 | fun f (x, NONE ) = NONE 4 | | f (x, SOME n) = 5 | if x >= 0 andalso x < base then SOME(n * base + x) 6 | else NONE 7 | in 8 | foldl f (SOME 0) 9 | end 10 | 11 | fun toBase base = let 12 | infix divMod 13 | fun a divMod b = (a div b, a mod b) 14 | 15 | fun swap (a, b) = (b, a) 16 | 17 | fun unfold f b = 18 | case f b of 19 | SOME(a, b') => a :: unfold f b' 20 | | NONE => [] 21 | 22 | fun f 0 = NONE 23 | | f x = SOME (swap (x divMod base)) 24 | in 25 | rev o (unfold f) 26 | end 27 | in 28 | if inBase < 2 29 | orelse outBase < 2 30 | orelse (List.length digits) = 0 31 | orelse (List.length digits) = (List.length (List.filter (fn x => x = 0) digits)) 32 | then NONE 33 | else case fromBase inBase digits of 34 | SOME v => SOME (toBase outBase v) 35 | | NONE => NONE 36 | end 37 | -------------------------------------------------------------------------------- /exercises/practice/all-your-base/all-your-base.sml: -------------------------------------------------------------------------------- 1 | fun rebase (inBase: int, outBase: int, digits: int list): int list option = 2 | raise Fail "'rebase' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/allergies/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies. 4 | 5 | An allergy test produces a single numeric score which contains the information about all the allergies the person has (that they were tested for). 6 | 7 | The list of items (and their value) that were tested are: 8 | 9 | - eggs (1) 10 | - peanuts (2) 11 | - shellfish (4) 12 | - strawberries (8) 13 | - tomatoes (16) 14 | - chocolate (32) 15 | - pollen (64) 16 | - cats (128) 17 | 18 | So if Tom is allergic to peanuts and chocolate, he gets a score of 34. 19 | 20 | Now, given just that score of 34, your program should be able to say: 21 | 22 | - Whether Tom is allergic to any one of those allergens listed above. 23 | - All the allergens Tom is allergic to. 24 | 25 | Note: a given score may include allergens **not** listed above (i.e. allergens that score 256, 512, 1024, etc.). 26 | Your program should ignore those components of the score. 27 | For example, if the allergy score is 257, your program should only report the eggs (1) allergy. 28 | -------------------------------------------------------------------------------- /exercises/practice/allergies/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "iHiD", 5 | "kytrinyx", 6 | "mcmillhj-wta", 7 | "sjwarner-bp", 8 | "snahor", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "allergies.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies.", 23 | "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", 24 | "source_url": "https://turing.edu" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/allergies/allergies.sml: -------------------------------------------------------------------------------- 1 | datatype allergen = Eggs 2 | | Peanuts 3 | | Shellfish 4 | | Strawberries 5 | | Tomatoes 6 | | Chocolate 7 | | Pollen 8 | | Cats 9 | 10 | fun allergicTo (score: int) (a: allergen): bool = 11 | raise Fail "'allergicTo' is not implemented" 12 | 13 | fun allergies (score: int): allergen list = 14 | raise Fail "'allergies' is not implemented" 15 | -------------------------------------------------------------------------------- /exercises/practice/anagram/.docs/instructions.append.md: -------------------------------------------------------------------------------- 1 | # Instructions Append 2 | 3 | You must return the anagrams in the same order as they are listed in the candidate words. 4 | -------------------------------------------------------------------------------- /exercises/practice/anagram/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a target word and one or more candidate words, your task is to find the candidates that are anagrams of the target. 4 | 5 | An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`. 6 | A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`. 7 | 8 | The target word and candidate words are made up of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`). 9 | Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `"StoP"` is not an anagram of `"sTOp"`. 10 | The words you need to find should be taken from the candidate words, using the same letter case. 11 | 12 | Given the target `"stone"` and the candidate words `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, and `"Seton"`, the anagram words you need to find are `"tones"`, `"notes"`, and `"Seton"`. 13 | -------------------------------------------------------------------------------- /exercises/practice/anagram/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | At a garage sale, you find a lovely vintage typewriter at a bargain price! 4 | Excitedly, you rush home, insert a sheet of paper, and start typing away. 5 | However, your excitement wanes when you examine the output: all words are garbled! 6 | For example, it prints "stop" instead of "post" and "least" instead of "stale." 7 | Carefully, you try again, but now it prints "spot" and "slate." 8 | After some experimentation, you find there is a random delay before each letter is printed, which messes up the order. 9 | You now understand why they sold it for so little money! 10 | 11 | You realize this quirk allows you to generate anagrams, which are words formed by rearranging the letters of another word. 12 | Pleased with your finding, you spend the rest of the day generating hundreds of anagrams. 13 | -------------------------------------------------------------------------------- /exercises/practice/anagram/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "iHiD", 5 | "kytrinyx", 6 | "mcmillhj-wta", 7 | "sjwarner-bp", 8 | "snahor", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "anagram.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Given a word and a list of possible anagrams, select the correct sublist.", 23 | "source": "Inspired by the Extreme Startup game", 24 | "source_url": "https://github.com/rchatley/extreme_startup" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/anagram/anagram.sml: -------------------------------------------------------------------------------- 1 | fun anagramsFor subject candidates = 2 | raise Fail "'anagramsFor' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | An [Armstrong number][armstrong-number] is a number that is the sum of its own digits each raised to the power of the number of digits. 4 | 5 | For example: 6 | 7 | - 9 is an Armstrong number, because `9 = 9^1 = 9` 8 | - 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1` 9 | - 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` 10 | - 154 is _not_ an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` 11 | 12 | Write some code to determine whether a number is an Armstrong number. 13 | 14 | [armstrong-number]: https://en.wikipedia.org/wiki/Narcissistic_number 15 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "armstrong-numbers.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Determine if a number is an Armstrong number.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Narcissistic_number" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | fun recurse (exponent: int) (base: int) (multiplier: int): int = 3 | if exponent = 0 then multiplier 4 | else recurse (exponent div 2) (base * base) (if exponent mod 2 = 0 then multiplier else base * multiplier) 5 | in 6 | fun power (exponent: int) (base: int): int = 7 | recurse exponent base 1 8 | end 9 | 10 | fun isArmstrongNumber (number: int): bool = 11 | let 12 | val sum: int list -> int = 13 | foldl op+ 0 14 | 15 | fun recurse (digits: int list) (n: int): bool = 16 | if n = 0 then 17 | let 18 | val count = length digits 19 | in 20 | number = sum (map (power count) digits) 21 | end 22 | else 23 | recurse ((n mod 10) :: digits) (n div 10) 24 | in 25 | recurse [] number 26 | end 27 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/armstrong-numbers.sml: -------------------------------------------------------------------------------- 1 | fun isArmstrongNumber (number: int): bool = 2 | raise Fail "'isArmstrongNumber' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/atbash-cipher/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "atbash-cipher.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East.", 23 | "source": "Wikipedia", 24 | "source_url": "https://en.wikipedia.org/wiki/Atbash" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/atbash-cipher/.meta/example.sml: -------------------------------------------------------------------------------- 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 33 | -------------------------------------------------------------------------------- /exercises/practice/atbash-cipher/atbash-cipher.sml: -------------------------------------------------------------------------------- 1 | fun decode (phrase: string): string = 2 | raise Fail "'decode' is not implemented" 3 | 4 | fun encode (phrase: string): string = 5 | raise Fail "'encode' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/binary-search/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You have stumbled upon a group of mathematicians who are also singer-songwriters. 4 | They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). 5 | 6 | You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. 7 | Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. 8 | 9 | You realize that you can use a binary search algorithm to quickly find a song given the title. 10 | 11 | [zero]: https://en.wikipedia.org/wiki/0 12 | [seventy-three]: https://en.wikipedia.org/wiki/73_(number) 13 | [kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) 14 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "binary-search.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Implement a binary search algorithm.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun find (haystack: int array, needle: int): int = 2 | let 3 | fun recurse (low: int, high: int): int = 4 | if low >= high then raise Fail "value not in array" 5 | else 6 | let 7 | val middle = (low + high) div 2 8 | val element = Array.sub (haystack, middle) 9 | in 10 | if needle < element then recurse (low, middle) 11 | else if needle > element then recurse (middle + 1, high) 12 | else middle 13 | end 14 | in 15 | recurse (0, Array.length haystack) 16 | end 17 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/binary-search.sml: -------------------------------------------------------------------------------- 1 | fun find (haystack: int array, needle: int): int = 2 | raise Fail "'find' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/binary/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Convert a binary number, represented as a string (e.g. '101010'), to its decimal equivalent using first principles. 4 | 5 | Implement binary to decimal conversion. Given a binary input 6 | string, your program should produce a decimal output. The 7 | program should handle invalid inputs. 8 | 9 | ## Note 10 | 11 | - Implement the conversion yourself. 12 | Do not use something else to perform the conversion for you. 13 | 14 | ## About Binary (Base-2) 15 | 16 | Decimal is a base-10 system. 17 | 18 | A number 23 in base 10 notation can be understood 19 | as a linear combination of powers of 10: 20 | 21 | - The rightmost digit gets multiplied by 10^0 = 1 22 | - The next number gets multiplied by 10^1 = 10 23 | - ... 24 | - The *n*th number gets multiplied by 10^*(n-1)*. 25 | - All these values are summed. 26 | 27 | So: `23 => 2*10^1 + 3*10^0 => 2*10 + 3*1 = 23 base 10` 28 | 29 | Binary is similar, but uses powers of 2 rather than powers of 10. 30 | 31 | So: `101 => 1*2^2 + 0*2^1 + 1*2^0 => 1*4 + 0*2 + 1*1 => 4 + 1 => 5 base 10`. 32 | -------------------------------------------------------------------------------- /exercises/practice/binary/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "blurb": "Convert a binary number, represented as a string (e.g. '101010'), to its decimal equivalent using first principles", 3 | "authors": [], 4 | "contributors": [ 5 | "iHiD", 6 | "kytrinyx", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "snahor", 10 | "sshine" 11 | ], 12 | "files": { 13 | "solution": [ 14 | "binary.sml" 15 | ], 16 | "test": [ 17 | "test.sml" 18 | ], 19 | "example": [ 20 | ".meta/example.sml" 21 | ] 22 | }, 23 | "source": "All of Computer Science", 24 | "source_url": "http://www.wolframalpha.com/input/?i=binary&a=*C.binary-_*MathWorld-" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/binary/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun decimal n = let 2 | val digits = List.map (fn c => (ord c) - 48) (explode n) 3 | val len = List.length digits 4 | 5 | fun validate [] = true 6 | | validate (d::ds) = if d <> 0 andalso d <> 1 then false 7 | else validate ds 8 | fun even n = (n mod 2) = 0 9 | fun int_pow a b = Real.toInt IEEEReal.TO_NEAREST (Math.pow (Real.fromInt(a), Real.fromInt(b))) 10 | fun f' [] mult acc = acc 11 | | f' (x::xs) mult acc = f' xs (mult - 1) (acc + (x * (int_pow 2 mult))) 12 | in 13 | if len = 0 orelse not(validate digits) then NONE 14 | else SOME (f' digits (len - 1) 0) 15 | end 16 | 17 | -------------------------------------------------------------------------------- /exercises/practice/binary/binary.sml: -------------------------------------------------------------------------------- 1 | fun decimal (binary: string): int option = 2 | raise Fail "'decimal' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/bob/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine what Bob will reply to someone when they say something to him or ask him a question. 4 | 5 | Bob only ever answers one of five things: 6 | 7 | - **"Sure."** 8 | This is his response if you ask him a question, such as "How are you?" 9 | The convention used for questions is that it ends with a question mark. 10 | - **"Whoa, chill out!"** 11 | This is his answer if you YELL AT HIM. 12 | The convention used for yelling is ALL CAPITAL LETTERS. 13 | - **"Calm down, I know what I'm doing!"** 14 | This is what he says if you yell a question at him. 15 | - **"Fine. Be that way!"** 16 | This is how he responds to silence. 17 | The convention used for silence is nothing, or various combinations of whitespace characters. 18 | - **"Whatever."** 19 | This is what he answers to anything else. 20 | -------------------------------------------------------------------------------- /exercises/practice/bob/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Bob is a [lackadaisical][] teenager. 4 | He likes to think that he's very cool. 5 | And he definitely doesn't get excited about things. 6 | That wouldn't be cool. 7 | 8 | When people talk to him, his responses are pretty limited. 9 | 10 | [lackadaisical]: https://www.collinsdictionary.com/dictionary/english/lackadaisical 11 | -------------------------------------------------------------------------------- /exercises/practice/bob/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "kytrinyx", 8 | "mcmillhj-wta", 9 | "sjwarner-bp", 10 | "sshine" 11 | ], 12 | "files": { 13 | "solution": [ 14 | "bob.sml" 15 | ], 16 | "test": [ 17 | "test.sml" 18 | ], 19 | "example": [ 20 | ".meta/example.sml" 21 | ] 22 | }, 23 | "blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited.", 24 | "source": "Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial.", 25 | "source_url": "https://pine.fm/LearnToProgram/?Chapter=06" 26 | } 27 | -------------------------------------------------------------------------------- /exercises/practice/bob/.meta/description.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Bob is a lackadaisical teenager. In conversation, his responses are very limited. 4 | 5 | Bob answers 'Sure.' if you ask him a question. 6 | 7 | He answers 'Whoa, chill out!' if you yell at him. 8 | 9 | He says 'Fine. Be that way!' if you address him without actually saying 10 | anything. 11 | 12 | He answers 'Whatever.' to anything else. 13 | -------------------------------------------------------------------------------- /exercises/practice/bob/.meta/example.sml: -------------------------------------------------------------------------------- 1 | val response = 2 | let 3 | open Char 4 | open List 5 | 6 | fun isQuestion chars = last (filter (not o isSpace) chars) = #"?" 7 | 8 | fun isYell chars = exists isAlpha chars andalso (map toUpper chars) = chars 9 | 10 | val isNothing = all isSpace 11 | 12 | fun response' chars = 13 | if isNothing chars 14 | then "Fine. Be that way!" 15 | else if isYell chars 16 | then if isQuestion chars 17 | then "Calm down, I know what I'm doing!" 18 | else "Whoa, chill out!" 19 | else if isQuestion chars 20 | then "Sure." 21 | else "Whatever." 22 | in 23 | response' o String.explode 24 | end 25 | -------------------------------------------------------------------------------- /exercises/practice/bob/bob.sml: -------------------------------------------------------------------------------- 1 | fun response s = 2 | raise Fail "'response' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/book-store/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "book-store.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "To try and encourage more sales of different books from a popular 5 book series, a bookshop has decided to offer discounts of multiple-book purchases.", 17 | "source": "Inspired by the harry potter kata from Cyber-Dojo.", 18 | "source_url": "https://cyber-dojo.org" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/book-store/book-store.sml: -------------------------------------------------------------------------------- 1 | fun total (basket: int list): int = 2 | raise Fail "'total' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/bottle-song/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "bottle-song.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Produce the lyrics to the popular children's repetitive song: Ten Green Bottles.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Ten_Green_Bottles" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/bottle-song/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun green (bottles: int): string = 2 | let 3 | val numbers = [ "No", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" ] 4 | 5 | val number = List.nth (numbers, bottles) 6 | 7 | val plural = if bottles = 1 then "" else "s" 8 | in 9 | number ^ " green bottle" ^ plural 10 | end 11 | 12 | fun verse (currentBottles: int): string = 13 | let 14 | val first = green(currentBottles) ^ " hanging on the wall,\n" 15 | 16 | val third = "And if one green bottle should accidentally fall,\n" 17 | 18 | val fourth = "There'll be " ^ String.map Char.toLower (green(currentBottles - 1)) ^ " hanging on the wall." 19 | in 20 | first ^ first ^ third ^ fourth 21 | end 22 | 23 | fun recite (startBottles: int, takeDown: int): string = 24 | let 25 | val suffix = if takeDown = 1 then "" else "\n\n" ^ recite (startBottles - 1, takeDown - 1) 26 | in 27 | verse(startBottles) ^ suffix 28 | end 29 | -------------------------------------------------------------------------------- /exercises/practice/bottle-song/bottle-song.sml: -------------------------------------------------------------------------------- 1 | fun recite (startBottles: int, takeDown: int): string = 2 | raise Fail "'recite' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/circular-buffer/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "glennj" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "circular-buffer.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "A data structure that uses a single, fixed-size buffer as if it were connected end-to-end.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Circular_buffer" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/circular-buffer/circular-buffer.sml: -------------------------------------------------------------------------------- 1 | structure CircularBuffer :> sig 2 | type buffer 3 | 4 | exception BufferFull 5 | exception BufferEmpty 6 | 7 | val create : int -> buffer 8 | val read : buffer -> int 9 | val write : buffer -> int -> unit 10 | val clear : buffer -> unit 11 | val overwrite : buffer -> int -> unit 12 | end = struct 13 | 14 | type buffer = unit (* TODO define the data structure *) 15 | 16 | exception BufferFull 17 | exception BufferEmpty 18 | 19 | fun create size = 20 | raise Fail "'create' is not implemented" 21 | 22 | fun read buff = 23 | raise Fail "'read' is not implemented" 24 | 25 | fun write buff value = 26 | raise Fail "'write' is not implemented" 27 | 28 | fun clear buff = 29 | raise Fail "'clear' is not implemented" 30 | 31 | fun overwrite buff value = 32 | raise Fail "'overwrite' is not implemented" 33 | end 34 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a positive integer, return the number of steps it takes to reach 1 according to the rules of the Collatz Conjecture. 4 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "collatz-conjecture.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", 23 | "source": "Wikipedia", 24 | "source_url": "https://en.wikipedia.org/wiki/Collatz_conjecture" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun even n = n mod 2 = 0 2 | 3 | fun collatz' i n = 4 | if n = 1 then i else 5 | collatz' (i + 1) (if even n 6 | then n div 2 7 | else 3 * n + 1) 8 | 9 | fun collatz n = 10 | if n < 1 then NONE else SOME (collatz' 0 n) 11 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/collatz-conjecture.sml: -------------------------------------------------------------------------------- 1 | fun collatz n = 2 | raise Fail "'collatz' has not been implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.1.1 *) 2 | 3 | use "testlib.sml"; 4 | use "collatz-conjecture.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "collatz-conjecture" [ 11 | test "zero collatz for one" 12 | (fn _ => collatz (1) |> Expect.equalTo (SOME 0)), 13 | 14 | test "divide if even" 15 | (fn _ => collatz (16) |> Expect.equalTo (SOME 4)), 16 | 17 | test "even and odd collatz" 18 | (fn _ => collatz (12) |> Expect.equalTo (SOME 9)), 19 | 20 | test "Large number of even and odd collatz" 21 | (fn _ => collatz (1000000) |> Expect.equalTo (SOME 152)), 22 | 23 | test "zero is an error" 24 | (fn _ => collatz (0) |> Expect.equalTo NONE), 25 | 26 | test "negative value is an error" 27 | (fn _ => collatz (~15) |> Expect.equalTo NONE) 28 | ] 29 | 30 | val _ = Test.run testsuite 31 | -------------------------------------------------------------------------------- /exercises/practice/darts/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "darts.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Calculate the points scored in a single toss of a Darts game.", 17 | "source": "Inspired by an exercise created by a professor Della Paolera in Argentina" 18 | } 19 | -------------------------------------------------------------------------------- /exercises/practice/darts/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun score (x: real, y: real): int = 2 | let 3 | val r = Math.sqrt(x * x + y * y) 4 | in 5 | if r <= 1.0 then 10 6 | else if r <= 5.0 then 5 7 | else if r <= 10.0 then 1 8 | else 0 9 | end 10 | -------------------------------------------------------------------------------- /exercises/practice/darts/darts.sml: -------------------------------------------------------------------------------- 1 | fun score (x: real, y: real): int = 2 | raise Fail "'score' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/diamond/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "diamond.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.", 23 | "source": "Seb Rose", 24 | "source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/diamond/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun rows (input: string): string list = 2 | let 3 | fun spaces n = List.tabulate (n, fn _ => #" ") 4 | 5 | fun index c = ord c - ord #"A" 6 | 7 | fun halfRow numcols c = spaces (numcols - index c - 1) @ [c] @ spaces (index c) 8 | 9 | fun mkRow numcols c = 10 | let 11 | val half = halfRow numcols c 12 | in 13 | implode (half @ tl (rev half)) 14 | end 15 | 16 | fun prevLetter c = chr (ord c - 1) 17 | 18 | val c = valOf (Char.fromString input) 19 | val numcols = index c + 1 20 | 21 | fun mkRows 0 _ acc = acc @ tl (rev acc) 22 | | mkRows i c acc = mkRows (i - 1) (prevLetter c) (mkRow numcols c :: acc) 23 | in 24 | mkRows numcols c [] 25 | end 26 | -------------------------------------------------------------------------------- /exercises/practice/diamond/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [202fb4cc-6a38-4883-9193-a29d5cb92076] 13 | description = "Degenerate case with a single 'A' row" 14 | 15 | [bd6a6d78-9302-42e9-8f60-ac1461e9abae] 16 | description = "Degenerate case with no row containing 3 distinct groups of spaces" 17 | 18 | [af8efb49-14ed-447f-8944-4cc59ce3fd76] 19 | description = "Smallest non-degenerate case with odd diamond side length" 20 | 21 | [e0c19a95-9888-4d05-86a0-fa81b9e70d1d] 22 | description = "Smallest non-degenerate case with even diamond side length" 23 | 24 | [82ea9aa9-4c0e-442a-b07e-40204e925944] 25 | description = "Largest possible diamond" 26 | -------------------------------------------------------------------------------- /exercises/practice/diamond/diamond.sml: -------------------------------------------------------------------------------- 1 | fun rows (input: string): string list = 2 | raise Fail "'rows' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. 4 | 5 | The square of the sum of the first ten natural numbers is 6 | (1 + 2 + ... + 10)² = 55² = 3025. 7 | 8 | The sum of the squares of the first ten natural numbers is 9 | 1² + 2² + ... + 10² = 385. 10 | 11 | Hence the difference between the square of the sum of the first ten natural numbers and the sum of the squares of the first ten natural numbers is 3025 - 385 = 2640. 12 | 13 | You are not expected to discover an efficient solution to this yourself from first principles; research is allowed, indeed, encouraged. 14 | Finding the best algorithm for the problem is a key skill in software engineering. 15 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "difference-of-squares.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.", 23 | "source": "Problem 6 at Project Euler", 24 | "source_url": "https://projecteuler.net/problem=6" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | fun square n = n * n 3 | fun sum n = n * (n + 1) div 2 4 | in 5 | val squareOfSum = square o sum 6 | fun sumOfSquares n = n * (n + 1) * (2 * n + 1) div 6 7 | fun differenceOfSquares n = squareOfSum n - sumOfSquares n 8 | end 9 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/difference-of-squares.sml: -------------------------------------------------------------------------------- 1 | fun squareOfSum n = 2 | raise Fail "'squareOfSum' is not implemented" 3 | 4 | fun differenceOfSquares n = 5 | raise Fail "'differenceOfSquares' is not implemented" 6 | 7 | fun sumOfSquares n = 8 | raise Fail "'sumOfSquares' is not implemented" 9 | -------------------------------------------------------------------------------- /exercises/practice/eliuds-eggs/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to count the number of 1 bits in the binary representation of a number. 4 | 5 | ## Restrictions 6 | 7 | Keep your hands off that bit-count functionality provided by your standard library! 8 | Solve this one yourself using other basic tools instead. 9 | -------------------------------------------------------------------------------- /exercises/practice/eliuds-eggs/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "BNAndras" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "eliuds-eggs.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Help Eliud count the number of eggs in her chicken coop by counting the number of 1 bits in a binary representation.", 17 | "source": "Christian Willner, Eric Willigers", 18 | "source_url": "https://forum.exercism.org/t/new-exercise-suggestion-pop-count/7632/5" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/eliuds-eggs/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun eggCount (number: int) : int = 2 | let 3 | fun recurse n acc = 4 | if n = 0 then acc 5 | else if (n mod 2) = 0 then recurse (n div 2) (acc) 6 | else recurse (n div 2) (acc + 1) 7 | in 8 | recurse number 0 9 | end 10 | -------------------------------------------------------------------------------- /exercises/practice/eliuds-eggs/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [559e789d-07d1-4422-9004-3b699f83bca3] 13 | description = "0 eggs" 14 | 15 | [97223282-f71e-490c-92f0-b3ec9e275aba] 16 | description = "1 egg" 17 | 18 | [1f8fd18f-26e9-4144-9a0e-57cdfc4f4ff5] 19 | description = "4 eggs" 20 | 21 | [0c18be92-a498-4ef2-bcbb-28ac4b06cb81] 22 | description = "13 eggs" 23 | -------------------------------------------------------------------------------- /exercises/practice/eliuds-eggs/eliuds-eggs.sml: -------------------------------------------------------------------------------- 1 | fun eggCount (number: int): int = 2 | raise Fail "'eggCount' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/eliuds-eggs/test.sml: -------------------------------------------------------------------------------- 1 | use "testlib.sml"; 2 | use "eliuds-eggs.sml"; 3 | 4 | infixr |> 5 | fun x |> f = f x 6 | 7 | val testsuite = 8 | describe "eliuds-eggs" [ 9 | test "0 eggs" 10 | (fn _ => eggCount 0 |> Expect.equalTo 0), 11 | 12 | test "1 egg" 13 | (fn _ => eggCount 16 |> Expect.equalTo 1), 14 | 15 | test "4 eggs" 16 | (fn _ => eggCount 89 |> Expect.equalTo 4), 17 | 18 | test "13 eggs" 19 | (fn _ => eggCount 2000000000 |> Expect.equalTo 13) 20 | ] 21 | 22 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/flatten-array/.docs/instructions.append.md: -------------------------------------------------------------------------------- 1 | # Hints 2 | 3 | You can think of this data structure as a [`Rose Tree`](https://en.wikipedia.org/wiki/Rose_tree). You are given a data type `'a tree` that represents this data structure. 4 | 5 | **Notes** 6 | - For this exercise `Empty` represents `null` 7 | - The nested list is represented by `List [...]`. 8 | - The input example is represented by `List [Elem 1, List [Elem 2, Elem 3, Empty, Elem 4], List [Empty], Elem 5]` 9 | -------------------------------------------------------------------------------- /exercises/practice/flatten-array/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Take a nested list and return a single flattened list with all values except nil/null. 4 | 5 | The challenge is to take an arbitrarily-deep nested list-like structure and produce a flattened structure without any nil/null values. 6 | 7 | For example: 8 | 9 | input: [1,[2,3,null,4],[null],5] 10 | 11 | output: [1,2,3,4,5] 12 | -------------------------------------------------------------------------------- /exercises/practice/flatten-array/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "iHiD", 5 | "kytrinyx", 6 | "mcmillhj-wta", 7 | "sjwarner-bp", 8 | "snahor", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "flatten-array.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Take a nested list and return a single list with all values except nil/null.", 23 | "source": "Interview Question", 24 | "source_url": "https://reference.wolfram.com/language/ref/Flatten.html" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/flatten-array/.meta/example.sml: -------------------------------------------------------------------------------- 1 | datatype 'a tree = Empty | Elem of 'a | List of 'a tree list 2 | 3 | fun flatten Empty = [] 4 | | flatten (Elem x) = [x] 5 | | flatten (List xs) = List.concat (map flatten xs) 6 | -------------------------------------------------------------------------------- /exercises/practice/flatten-array/flatten-array.sml: -------------------------------------------------------------------------------- 1 | (* Rose tree *) 2 | datatype 'a tree = Empty | Elem of 'a | List of 'a tree list 3 | 4 | fun flatten tree = 5 | raise Fail "'flatten' has not been implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/food-chain/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "food-chain.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Generate the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly'.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/There_Was_an_Old_Lady_Who_Swallowed_a_Fly" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/food-chain/food-chain.sml: -------------------------------------------------------------------------------- 1 | fun recite (startVerse: int, endVerse: int): string = 2 | raise Fail "'recite' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/gigasecond/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine the date and time one gigasecond after a certain date. 4 | 5 | A gigasecond is one thousand million seconds. 6 | That is a one with nine zeros after it. 7 | 8 | If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. 9 | -------------------------------------------------------------------------------- /exercises/practice/gigasecond/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "rainij" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "gigasecond.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a moment, determine the moment that would be after a gigasecond has passed.", 17 | "source": "Chapter 9 in Chris Pine's online Learn to Program tutorial.", 18 | "source_url": "https://pine.fm/LearnToProgram/?Chapter=09" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/gigasecond/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [92fbe71c-ea52-4fac-bd77-be38023cacf7] 13 | description = "date only specification of time" 14 | 15 | [6d86dd16-6f7a-47be-9e58-bb9fb2ae1433] 16 | description = "second test for date only specification of time" 17 | 18 | [77eb8502-2bca-4d92-89d9-7b39ace28dd5] 19 | description = "third test for date only specification of time" 20 | 21 | [c9d89a7d-06f8-4e28-a305-64f1b2abc693] 22 | description = "full time specified" 23 | 24 | [09d4e30e-728a-4b52-9005-be44a58d9eba] 25 | description = "full time with day roll-over" 26 | 27 | [fcec307c-7529-49ab-b0fe-20309197618a] 28 | description = "does not mutate the input" 29 | include = false 30 | -------------------------------------------------------------------------------- /exercises/practice/gigasecond/gigasecond.sml: -------------------------------------------------------------------------------- 1 | fun add (moment: string): string = 2 | raise Fail "'add' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/gigasecond/test.sml: -------------------------------------------------------------------------------- 1 | use "testlib.sml"; 2 | use "gigasecond.sml"; 3 | 4 | infixr |> 5 | fun x |> f = f x 6 | 7 | val testsuite = 8 | describe "gigasecond" [ 9 | test "date only specification of time" 10 | (fn _ => add "2011-04-25" |> Expect.equalTo "2043-01-01T01:46:40"), 11 | 12 | test "second test for date only specification of time" 13 | (fn _ => add "1977-06-13" |> Expect.equalTo "2009-02-19T01:46:40"), 14 | 15 | test "third test for date only specification of time" 16 | (fn _ => add "1959-07-19" |> Expect.equalTo "1991-03-27T01:46:40"), 17 | 18 | test "full time specified" 19 | (fn _ => add "2015-01-24T22:00:00" |> Expect.equalTo "2046-10-02T23:46:40"), 20 | 21 | test "full time with day roll-over" 22 | (fn _ => add "2015-01-24T23:59:59" |> Expect.equalTo "2046-10-03T01:46:39") 23 | ] 24 | 25 | val _ = Test.run testsuite 26 | -------------------------------------------------------------------------------- /exercises/practice/grains/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Calculate the number of grains of wheat on a chessboard. 4 | 5 | A chessboard has 64 squares. 6 | Square 1 has one grain, square 2 has two grains, square 3 has four grains, and so on, doubling each time. 7 | 8 | Write code that calculates: 9 | 10 | - the number of grains on a given square 11 | - the total number of grains on the chessboard 12 | -------------------------------------------------------------------------------- /exercises/practice/grains/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | There once was a wise servant who saved the life of a prince. 4 | The king promised to pay whatever the servant could dream up. 5 | Knowing that the king loved chess, the servant told the king he would like to have grains of wheat. 6 | One grain on the first square of a chessboard, with the number of grains doubling on each successive square. 7 | -------------------------------------------------------------------------------- /exercises/practice/grains/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "grains.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Calculate the number of grains of wheat on a chessboard given that the number on each square doubles.", 17 | "source": "The CodeRanch Cattle Drive, Assignment 6", 18 | "source_url": "https://web.archive.org/web/20240908084142/https://coderanch.com/wiki/718824/Grains" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/grains/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | fun power2 (k: int): LargeInt.int = 3 | if k = 0 then 1 4 | else 2 * power2 (k - 1) 5 | in 6 | fun square (n: int): string = 7 | if n < 1 orelse n > 64 then raise Fail "square must be between 1 and 64" 8 | else LargeInt.toString (power2 (n - 1)) 9 | 10 | fun total (): string = 11 | LargeInt.toString ((power2 64) - 1) 12 | end 13 | -------------------------------------------------------------------------------- /exercises/practice/grains/grains.sml: -------------------------------------------------------------------------------- 1 | fun square (n: int): string = 2 | raise Fail "'square' is not implemented" 3 | 4 | fun total (): string = 5 | raise Fail "'total' is not implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Calculate the Hamming distance between two DNA strands. 4 | 5 | We read DNA using the letters C, A, G and T. 6 | Two strands might look like this: 7 | 8 | GAGCCTACTAACGGGAT 9 | CATCGTAATGACGGCCT 10 | ^ ^ ^ ^ ^ ^^ 11 | 12 | They have 7 differences, and therefore the Hamming distance is 7. 13 | 14 | ## Implementation notes 15 | 16 | The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work. 17 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Your body is made up of cells that contain DNA. 4 | Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. 5 | In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! 6 | 7 | When cells divide, their DNA replicates too. 8 | Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. 9 | If we compare two strands of DNA and count the differences between them, we can see how many mistakes occurred. 10 | This is known as the "Hamming distance". 11 | 12 | The Hamming distance is useful in many areas of science, not just biology, so it's a nice phrase to be familiar with :) 13 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "hanjiexi", 5 | "iHiD", 6 | "kytrinyx", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "snahor", 10 | "sshine" 11 | ], 12 | "files": { 13 | "solution": [ 14 | "hamming.sml" 15 | ], 16 | "test": [ 17 | "test.sml" 18 | ], 19 | "example": [ 20 | ".meta/example.sml" 21 | ] 22 | }, 23 | "blurb": "Calculate the Hamming distance between two DNA strands.", 24 | "source": "The Calculating Point Mutations problem at Rosalind", 25 | "source_url": "https://rosalind.info/problems/hamm/" 26 | } 27 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun distance (strand1: string, strand2: string): int option = 2 | SOME (ListPair.foldlEq 3 | (fn (a, b, count) => if a = b then count else count+1) 0 4 | (explode strand1, explode strand2)) 5 | handle UnequalLengths => NONE 6 | -------------------------------------------------------------------------------- /exercises/practice/hamming/hamming.sml: -------------------------------------------------------------------------------- 1 | fun distance (strand1: string, strand2: string): int option = 2 | raise Fail "'distance' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | The classical introductory exercise. 4 | Just say "Hello, World!". 5 | 6 | ["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. 7 | 8 | The objectives are simple: 9 | 10 | - Modify the provided code so that it produces the string "Hello, World!". 11 | - Run the test suite and make sure that it succeeds. 12 | - Submit your solution and check it at the website. 13 | 14 | If everything goes well, you will be ready to fetch your first real exercise. 15 | 16 | [hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program 17 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "hello-world.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", 23 | "source": "This is an exercise to introduce users to using Exercism", 24 | "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun hello () = "Hello, World!" 2 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [af9ffe10-dc13-42d8-a742-e7bdafac449d] 13 | description = "Say Hi!" 14 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/hello-world.sml: -------------------------------------------------------------------------------- 1 | fun hello () = "Goodbye, Mars!" 2 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "hello-world.sml"; 4 | use "testlib.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "hello-world" [ 11 | test "Say Hi!" 12 | (fn _ => hello () |> Expect.equalTo "Hello, World!") 13 | ] 14 | 15 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/house/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "house.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Output the nursery rhyme 'This is the House that Jack Built'.", 17 | "source": "British nursery rhyme", 18 | "source_url": "https://en.wikipedia.org/wiki/This_Is_The_House_That_Jack_Built" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/house/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun recite (startVerse: int, endVerse: int): string = 2 | let 3 | val offsets = [ 0, 389, 368, 351, 331, 310, 267, 232, 190, 145, 99, 62, 8 ] 4 | 5 | val offset = List.nth (offsets, startVerse) 6 | 7 | val lyrics = "This is the horse and the hound and the horn that belonged to the farmer sowing his corn that kept the rooster that crowed in the morn that woke the priest all shaven and shorn that married the man all tattered and torn that kissed the maiden all forlorn that milked the cow with the crumpled horn that tossed the dog that worried the cat that killed the rat that ate the malt that lay in the house that Jack built." 8 | 9 | val lyric = String.substring (lyrics, offset, String.size lyrics - offset) 10 | 11 | val suffix = if startVerse = endVerse then "" else "\n" ^ recite (startVerse + 1, endVerse) 12 | in 13 | "This is " ^ lyric ^ suffix 14 | end 15 | -------------------------------------------------------------------------------- /exercises/practice/house/house.sml: -------------------------------------------------------------------------------- 1 | fun recite (startVerse: int, endVerse: int): string = 2 | raise Fail "'recite' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "isbn-verifier.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Check if a given string is a valid ISBN-10 number.", 17 | "source": "Converting a string into a number and some basic processing utilizing a relatable real world example.", 18 | "source_url": "https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/.meta/example.sml: -------------------------------------------------------------------------------- 1 | val isValid: string -> bool = 2 | let 3 | fun digitValue (c: char): int = 4 | Char.ord c - Char.ord #"0" 5 | val excludeHyphens: char list -> char list = 6 | List.filter (fn c => c <> #"-") 7 | fun recurse (weight: int) (total: int) (l: char list): bool = 8 | case (weight, l) of 9 | (0, nil) => total mod 11 = 0 10 | | (_, nil) => false 11 | | (1, #"X" :: nil) => total mod 11 = 1 12 | | (_, c :: rest) => Char.isDigit c andalso recurse (weight - 1) (total + weight * (digitValue c)) rest 13 | in 14 | recurse 10 0 o excludeHyphens o String.explode 15 | end 16 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/isbn-verifier.sml: -------------------------------------------------------------------------------- 1 | fun isValid (isbn: string): bool = 2 | raise Fail "'isValid' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Determine if a word or phrase is an isogram. 4 | 5 | An isogram (also known as a "non-pattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times. 6 | 7 | Examples of isograms: 8 | 9 | - lumberjacks 10 | - background 11 | - downstream 12 | - six-year-old 13 | 14 | The word _isograms_, however, is not an isogram, because the s repeats. 15 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "isogram.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Determine if a word or phrase is an isogram.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Isogram" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.meta/example.sml: -------------------------------------------------------------------------------- 1 | val isIsogram: string -> bool = 2 | let 3 | val a = Char.ord #"a" 4 | 5 | (* We represent each letter by setting a different bit, 6 | * for example the letter c is encoded as ...00100 binary. 7 | *) 8 | fun letterValue (c: char): word = 9 | Word.<<(0wx1, Word.fromInt(Char.ord (Char.toLower c) - a)) 10 | 11 | (* seen represents the set of letters that have been seen 12 | * so far. For example, if we have seen the letters d and c, 13 | * this is encoded as ...01100 binary. 14 | * If we find a letter in l that matches a letter already 15 | * seen, we return false. 16 | *) 17 | fun recurse (seen: word) (l: char list): bool = 18 | case l of 19 | nil => true 20 | | c :: rest => 21 | let 22 | val seen' = Word.orb (seen, letterValue c) 23 | in 24 | seen' <> seen andalso recurse seen' rest 25 | end 26 | in 27 | recurse 0wx0 o List.filter Char.isAlpha o String.explode 28 | end 29 | -------------------------------------------------------------------------------- /exercises/practice/isogram/isogram.sml: -------------------------------------------------------------------------------- 1 | fun isIsogram s = 2 | raise Fail "'isIsogram' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/kindergarten-garden/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The kindergarten class is learning about growing plants. 4 | The teacher thought it would be a good idea to give the class seeds to plant and grow in the dirt. 5 | To this end, the children have put little cups along the window sills and planted one type of plant in each cup. 6 | The children got to pick their favorites from four available types of seeds: grass, clover, radishes, and violets. 7 | -------------------------------------------------------------------------------- /exercises/practice/kindergarten-garden/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "kindergarten-garden.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a diagram, determine which plants each child in the kindergarten class is responsible for.", 17 | "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", 18 | "source_url": "https://turing.edu" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/kindergarten-garden/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun plants (diagram: string) (student: string): string list = 2 | let 3 | val index = ord (String.sub (student, 0)) - ord #"A" 4 | 5 | val first = 2 * index 6 | val second = 2 * index + 1 7 | val third = (1 + size diagram) div 2 + 2 * index 8 | val fourth = (1 + size diagram) div 2 + 2 * index + 1 9 | 10 | fun plant (place: int): string = 11 | let 12 | val c = String.sub (diagram, place) 13 | in 14 | if c = #"G" then "grass" 15 | else if c = #"C" then "clover" 16 | else if c = #"R" then "radishes" 17 | else if c = #"V" then "violets" 18 | else raise Fail "unknown plant" 19 | end 20 | in 21 | [plant first, plant second, plant third, plant fourth] 22 | end 23 | -------------------------------------------------------------------------------- /exercises/practice/kindergarten-garden/kindergarten-garden.sml: -------------------------------------------------------------------------------- 1 | fun plants (diagram: string) (student: string): string list = 2 | raise Fail "'plants' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/knapsack/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine which items to take so that the total value of her selection is maximized, taking into account the knapsack's carrying capacity. 4 | 5 | Items will be represented as a list of items. 6 | Each item will have a weight and value. 7 | All values given will be strictly positive. 8 | Lhakpa can take only one of each item. 9 | 10 | For example: 11 | 12 | ```text 13 | Items: [ 14 | { "weight": 5, "value": 10 }, 15 | { "weight": 4, "value": 40 }, 16 | { "weight": 6, "value": 30 }, 17 | { "weight": 4, "value": 50 } 18 | ] 19 | 20 | Knapsack Maximum Weight: 10 21 | ``` 22 | 23 | For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. 24 | In this example, Lhakpa should take the second and fourth item to maximize her value, which, in this case, is 90. 25 | She cannot get more than 90 as her knapsack has a weight limit of 10. 26 | -------------------------------------------------------------------------------- /exercises/practice/knapsack/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Lhakpa is a [Sherpa][sherpa] mountain guide and porter. 4 | After months of careful planning, the expedition Lhakpa works for is about to leave. 5 | She will be paid the value she carried to the base camp. 6 | 7 | In front of her are many items, each with a value and weight. 8 | Lhakpa would gladly take all of the items, but her knapsack can only hold so much weight. 9 | 10 | [sherpa]: https://en.wikipedia.org/wiki/Sherpa_people#Mountaineering 11 | -------------------------------------------------------------------------------- /exercises/practice/knapsack/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "kahgoh" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "knapsack.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a knapsack that can only carry a certain weight, determine which items to put in the knapsack in order to maximize their combined value.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Knapsack_problem" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/knapsack/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun itemMaxValue(i: {value: int, weight: int}, prevValues, cap) = 2 | let 3 | val valueWithout = List.nth(prevValues, cap) 4 | in 5 | if (#weight i > cap) then 6 | valueWithout 7 | else 8 | let 9 | val valueWith = List.nth(prevValues, cap - #weight i) + #value i 10 | in 11 | Int.max(valueWith, valueWithout) 12 | end 13 | end; 14 | 15 | fun nextValues(i: {value: int, weight: int}, prevValues, cap, acc) : int list = 16 | if cap < 0 then 17 | acc 18 | else 19 | let 20 | val itemValue = itemMaxValue(i, prevValues, cap) 21 | in 22 | nextValues(i, prevValues, cap - 1, itemValue::acc) 23 | end; 24 | 25 | fun calculateValues([], values) = values 26 | | calculateValues((i :: next), values) = 27 | let 28 | val valuesForNext = nextValues(i, values, (List.length values) - 1, []) 29 | in 30 | calculateValues(next, valuesForNext) 31 | end; 32 | 33 | fun maximumValue([], _) = 0 34 | | maximumValue(items, maximumWeight): int = 35 | let 36 | val size : int = maximumWeight + 1 37 | val initial : int list = List.tabulate(size, fn _ => 0) 38 | in 39 | List.last(calculateValues(items, initial)) 40 | end; -------------------------------------------------------------------------------- /exercises/practice/knapsack/knapsack.sml: -------------------------------------------------------------------------------- 1 | fun maximumValue (items: {value: int, weight: int} list, maximumWeight: int): int = 2 | raise Fail "'maximumValue' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/largest-series-product/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to look for patterns in the long sequence of digits in the encrypted signal. 4 | 5 | The technique you're going to use here is called the largest series product. 6 | 7 | Let's define a few terms, first. 8 | 9 | - **input**: the sequence of digits that you need to analyze 10 | - **series**: a sequence of adjacent digits (those that are next to each other) that is contained within the input 11 | - **span**: how many digits long each series is 12 | - **product**: what you get when you multiply numbers together 13 | 14 | Let's work through an example, with the input `"63915"`. 15 | 16 | - To form a series, take adjacent digits in the original input. 17 | - If you are working with a span of `3`, there will be three possible series: 18 | - `"639"` 19 | - `"391"` 20 | - `"915"` 21 | - Then we need to calculate the product of each series: 22 | - The product of the series `"639"` is 162 (`6 × 3 × 9 = 162`) 23 | - The product of the series `"391"` is 27 (`3 × 9 × 1 = 27`) 24 | - The product of the series `"915"` is 45 (`9 × 1 × 5 = 45`) 25 | - 162 is bigger than both 27 and 45, so the largest series product of `"63915"` is from the series `"639"`. 26 | So the answer is **162**. 27 | -------------------------------------------------------------------------------- /exercises/practice/largest-series-product/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a government agency that has intercepted a series of encrypted communication signals from a group of bank robbers. 4 | The signals contain a long sequence of digits. 5 | Your team needs to use various digital signal processing techniques to analyze the signals and identify any patterns that may indicate the planning of a heist. 6 | -------------------------------------------------------------------------------- /exercises/practice/largest-series-product/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "glennj" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "largest-series-product.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.", 17 | "source": "A variation on Problem 8 at Project Euler", 18 | "source_url": "https://projecteuler.net/problem=8" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/largest-series-product/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | infix |> (* left-associative *) 3 | fun (x |> f) = f x 4 | 5 | val product = List.foldl op* 1 6 | val max = List.foldl Int.max ~1 7 | fun spans _ [] = [] 8 | | spans span ns = 9 | if span > length ns then [] 10 | else (List.take (ns, span)) :: spans span (tl ns) 11 | in 12 | fun largestProduct (digits: string, span: int): int = 13 | if span > size digits then raise Fail "span must not exceed string length" 14 | else if span < 0 then raise Fail "span must not be negative" 15 | else if span = 0 then 1 16 | else explode digits 17 | |> List.map (valOf o Int.fromString o str) 18 | |> spans span 19 | |> List.map product 20 | |> max 21 | handle Option => raise Fail "digits input must only contain digits" 22 | end 23 | -------------------------------------------------------------------------------- /exercises/practice/largest-series-product/largest-series-product.sml: -------------------------------------------------------------------------------- 1 | fun largestProduct (digits: string, span: int): int = 2 | raise Fail "'largestProduct' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/leap/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine whether a given year is a leap year. 4 | -------------------------------------------------------------------------------- /exercises/practice/leap/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | A leap year (in the Gregorian calendar) occurs: 4 | 5 | - In every year that is evenly divisible by 4. 6 | - Unless the year is evenly divisible by 100, in which case it's only a leap year if the year is also evenly divisible by 400. 7 | 8 | Some examples: 9 | 10 | - 1997 was not a leap year as it's not divisible by 4. 11 | - 1900 was not a leap year as it's not divisible by 400. 12 | - 2000 was a leap year! 13 | 14 | ~~~~exercism/note 15 | For a delightful, four-minute explanation of the whole phenomenon of leap years, check out [this YouTube video](https://www.youtube.com/watch?v=xX96xng7sAE). 16 | ~~~~ 17 | -------------------------------------------------------------------------------- /exercises/practice/leap/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "leap.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Determine whether a given year is a leap year.", 23 | "source": "CodeRanch Cattle Drive, Assignment 3", 24 | "source_url": "https://web.archive.org/web/20240907033714/https://coderanch.com/t/718816/Leap" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/leap/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun isLeapYear year = 2 | year mod 400 = 0 orelse (year mod 4 = 0 andalso year mod 100 <> 0) 3 | -------------------------------------------------------------------------------- /exercises/practice/leap/leap.sml: -------------------------------------------------------------------------------- 1 | fun isLeapYear year = 2 | raise Fail "'isLeapYear' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/leap/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.4.0 *) 2 | 3 | use "testlib.sml"; 4 | use "leap.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "leap" [ 11 | test "year not divisible by 4: common year" 12 | (fn _ => isLeapYear (2015) |> Expect.falsy), 13 | 14 | test "year divisible by 4, not divisible by 100: leap year" 15 | (fn _ => isLeapYear (1996) |> Expect.truthy), 16 | 17 | test "year divisible by 100, not divisible by 400: common year" 18 | (fn _ => isLeapYear (2100) |> Expect.falsy), 19 | 20 | test "year divisible by 400: leap year" 21 | (fn _ => isLeapYear (2000) |> Expect.truthy), 22 | 23 | test "year divisible by 200, not divisible by 400: common year" 24 | (fn _ => isLeapYear (1800) |> Expect.falsy) 25 | ] 26 | 27 | val _ = Test.run testsuite 28 | -------------------------------------------------------------------------------- /exercises/practice/list-ops/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "list-ops.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Implement basic list operations." 23 | } 24 | -------------------------------------------------------------------------------- /exercises/practice/list-ops/.meta/example.sml: -------------------------------------------------------------------------------- 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))) 35 | -------------------------------------------------------------------------------- /exercises/practice/list-ops/list-ops.sml: -------------------------------------------------------------------------------- 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" 24 | -------------------------------------------------------------------------------- /exercises/practice/luhn/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | At the Global Verification Authority, you've just been entrusted with a critical assignment. 4 | Across the city, from online purchases to secure logins, countless operations rely on the accuracy of numerical identifiers like credit card numbers, bank account numbers, transaction codes, and tracking IDs. 5 | The Luhn algorithm is a simple checksum formula used to help identify mistyped numbers. 6 | 7 | A batch of identifiers has just arrived on your desk. 8 | All of them must pass the Luhn test to ensure they're legitimate. 9 | If any fail, they'll be flagged as invalid, preventing mistakes such as incorrect transactions or failed account verifications. 10 | 11 | Can you ensure this is done right? The integrity of many services depends on you. 12 | -------------------------------------------------------------------------------- /exercises/practice/luhn/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "luhn.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a number determine whether or not it is valid per the Luhn formula.", 17 | "source": "The Luhn Algorithm on Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Luhn_algorithm" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/luhn/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | fun contribution (digit: char, count: int): int = 3 | let 4 | val number = ord digit - ord #"0" 5 | in 6 | if count mod 2 = 0 then number 7 | else if 2 * number > 9 then 2 * number - 9 8 | else 2 * number 9 | end 10 | 11 | fun recurse (count: int) (total: int) (l: char list): bool = 12 | case l of 13 | nil => count > 1 andalso total mod 10 = 0 14 | | #" " :: rest => recurse count total rest 15 | | first :: rest => 16 | if Char.isDigit first then recurse (count + 1) (total + contribution (first, count)) rest 17 | else false 18 | in 19 | val valid: string -> bool = 20 | recurse 0 0 o rev o explode 21 | end 22 | -------------------------------------------------------------------------------- /exercises/practice/luhn/luhn.sml: -------------------------------------------------------------------------------- 1 | fun valid (value: string): bool = 2 | raise Fail "'valid' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/matching-brackets/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. 4 | Any other characters should be ignored. 5 | For example, `"{what is (42)}?"` is balanced and `"[text}"` is not. 6 | -------------------------------------------------------------------------------- /exercises/practice/matching-brackets/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You're given the opportunity to write software for the Bracketeer™, an ancient but powerful mainframe. 4 | The software that runs on it is written in a proprietary language. 5 | Much of its syntax is familiar, but you notice _lots_ of brackets, braces and parentheses. 6 | Despite the Bracketeer™ being powerful, it lacks flexibility. 7 | If the source code has any unbalanced brackets, braces or parentheses, the Bracketeer™ crashes and must be rebooted. 8 | To avoid such a scenario, you start writing code that can verify that brackets, braces, and parentheses are balanced before attempting to run it on the Bracketeer™. 9 | -------------------------------------------------------------------------------- /exercises/practice/matching-brackets/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sshine" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp" 9 | ], 10 | "files": { 11 | "solution": [ 12 | "matching-brackets.sml" 13 | ], 14 | "test": [ 15 | "test.sml" 16 | ], 17 | "example": [ 18 | ".meta/example.sml" 19 | ] 20 | }, 21 | "blurb": "Make sure the brackets and braces all match.", 22 | "source": "Ginna Baker" 23 | } 24 | -------------------------------------------------------------------------------- /exercises/practice/matching-brackets/.meta/example.sml: -------------------------------------------------------------------------------- 1 | datatype ('a, 'b) either = Left of 'a | Right of 'b 2 | 3 | fun foldUntil f finish e0 s = 4 | let fun go i e = 5 | if i < size s 6 | then case f (e, String.sub (s, i)) of 7 | Left done => done 8 | | Right e' => go (i+1) e' 9 | else finish e 10 | in go 0 e0 end 11 | 12 | fun balance (stack, c) = 13 | if c = #"[" orelse c = #"{" orelse c = #"(" then Right (c::stack) else 14 | case (stack, c) of 15 | (#"["::bs, #"]") => Right bs 16 | | (#"{"::bs, #"}") => Right bs 17 | | (#"("::bs, #")") => Right bs 18 | | _ => if c = #"]" orelse c = #"}" orelse c = #")" then Left false else Right stack 19 | 20 | fun isEmpty [] = true 21 | | isEmpty _ = false 22 | 23 | val isBalanced = 24 | foldUntil balance isEmpty [] 25 | -------------------------------------------------------------------------------- /exercises/practice/matching-brackets/matching-brackets.sml: -------------------------------------------------------------------------------- 1 | fun isBalanced s = 2 | raise Fail "'isBalanced' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a string representing a matrix of numbers, return the rows and columns of that matrix. 4 | 5 | So given a string with embedded newlines like: 6 | 7 | ```text 8 | 9 8 7 9 | 5 3 2 10 | 6 6 7 11 | ``` 12 | 13 | representing this matrix: 14 | 15 | ```text 16 | 1 2 3 17 | |--------- 18 | 1 | 9 8 7 19 | 2 | 5 3 2 20 | 3 | 6 6 7 21 | ``` 22 | 23 | your code should be able to spit out: 24 | 25 | - A list of the rows, reading each row left-to-right while moving top-to-bottom across the rows, 26 | - A list of the columns, reading each column top-to-bottom while moving from left-to-right. 27 | 28 | The rows for our example matrix: 29 | 30 | - 9, 8, 7 31 | - 5, 3, 2 32 | - 6, 6, 7 33 | 34 | And its columns: 35 | 36 | - 9, 5, 6 37 | - 8, 3, 6 38 | - 7, 2, 7 39 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "matrix.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a string representing a matrix of numbers, return the rows and columns of that matrix.", 17 | "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", 18 | "source_url": "https://turing.edu" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | val lines: string -> string list = 3 | String.tokens (fn (c: char) => c = #"\n") 4 | 5 | val cells: string -> string list = 6 | String.tokens (fn (c: char) => c = #" ") 7 | 8 | fun extract (index: int) (l: string list): string = 9 | List.nth (l, index - 1) 10 | in 11 | fun row (s: string, index: int): int list = 12 | map (valOf o Int.fromString) ((cells o extract index o lines) s) 13 | 14 | fun column (s: string, index: int): int list = 15 | map (valOf o Int.fromString o extract index o cells) (lines s) 16 | end 17 | 18 | -------------------------------------------------------------------------------- /exercises/practice/matrix/matrix.sml: -------------------------------------------------------------------------------- 1 | fun row (s: string, index: int): int list = 2 | raise Fail "'row' is not implemented" 3 | 4 | fun column (s: string, index: int): int list = 5 | raise Fail "'column' is not implemented" 6 | 7 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.docs/instructions.append.md: -------------------------------------------------------------------------------- 1 | # Hints 2 | 3 | If the argument is less than `1`, return [`NONE`](https://smlfamily.github.io/Basis/option.html#SIG:OPTION.option:TY:SPEC). 4 | 5 | Some of these concepts may be helpful: 6 | 7 | - [Lazy evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation) 8 | - Sieving (for instance [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) 9 | - Primality by [trial division](https://en.wikipedia.org/wiki/Trial_division) 10 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a number n, determine what the nth prime is. 4 | 5 | By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. 6 | 7 | If your language provides methods in the standard library to deal with prime numbers, pretend they don't exist and implement them yourself. 8 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "iHiD", 5 | "kytrinyx", 6 | "mcmillhj-wta", 7 | "sjwarner-bp", 8 | "snahor", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "nth-prime.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Given a number n, determine what the nth prime is.", 23 | "source": "A variation on Problem 7 at Project Euler", 24 | "source_url": "https://projecteuler.net/problem=7" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.meta/example.sml: -------------------------------------------------------------------------------- 1 | (* Since there are infinitely many primes, there's no need for a Nil. *) 2 | datatype 'a stream = Cons of 'a * (unit -> 'a stream) 3 | 4 | (* Filtering a stream with predicate `p` gives a new stream. *) 5 | fun filter p (Cons (x, stream)) = 6 | if p x 7 | then Cons (x, fn () => filter p (stream ())) 8 | else filter p (stream ()) 9 | 10 | (* Getting the nth element of a stream. *) 11 | fun nth (Cons (x, _), 0) = x 12 | | nth (Cons (_, stream), n) = nth (stream (), n-1) 13 | 14 | (* Get an `int stream` with multiples of `i` removed. *) 15 | fun crossOut i = 16 | filter (fn n => n mod i <> 0) 17 | 18 | (* Produce a sieve where multiples are iteratively removed. *) 19 | fun sieve (Cons (n, stream)) = 20 | Cons (n, fn () => sieve (crossOut n (stream ()))) 21 | 22 | (* An `int stream` of natural numbers from `i`. *) 23 | fun nats i = 24 | Cons (i, fn () => nats (i+1)) 25 | 26 | (* The nth prime is the nth element of the stream sieve. *) 27 | fun nthPrime n = 28 | if n < 1 29 | then NONE 30 | else SOME (nth (sieve (nats 2), n - 1)) 31 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [75c65189-8aef-471a-81de-0a90c728160c] 13 | description = "first prime" 14 | 15 | [2c38804c-295f-4701-b728-56dea34fd1a0] 16 | description = "second prime" 17 | 18 | [56692534-781e-4e8c-b1f9-3e82c1640259] 19 | description = "sixth prime" 20 | 21 | [fce1e979-0edb-412d-93aa-2c744e8f50ff] 22 | description = "big prime" 23 | 24 | [bd0a9eae-6df7-485b-a144-80e13c7d55b2] 25 | description = "there is no zeroth prime" 26 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/nth-prime.sml: -------------------------------------------------------------------------------- 1 | fun nthPrime n = 2 | raise Fail "'prime' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "testlib.sml"; 4 | use "nth-prime.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "nth-prime" [ 11 | test "first prime" 12 | (fn _ => nthPrime 1 |> Expect.equalTo (SOME 2)), 13 | 14 | test "second prime" 15 | (fn _ => nthPrime 2 |> Expect.equalTo (SOME 3)), 16 | 17 | test "sixth prime" 18 | (fn _ => nthPrime 6 |> Expect.equalTo (SOME 13)), 19 | 20 | test "big prime" 21 | (fn _ => nthPrime 10001 |> Expect.equalTo (SOME 104743)), 22 | 23 | test "there is no zeroth prime" 24 | (fn _ => nthPrime 0 |> Expect.equalTo NONE) 25 | ] 26 | 27 | val _ = Test.run testsuite 28 | -------------------------------------------------------------------------------- /exercises/practice/nucleotide-count/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Each of us inherits from our biological parents a set of chemical instructions known as DNA that influence how our bodies are constructed. 4 | All known life depends on DNA! 5 | 6 | > Note: You do not need to understand anything about nucleotides or DNA to complete this exercise. 7 | 8 | DNA is a long chain of other chemicals and the most important are the four nucleotides, adenine, cytosine, guanine and thymine. 9 | A single DNA chain can contain billions of these four nucleotides and the order in which they occur is important! 10 | We call the order of these nucleotides in a bit of DNA a "DNA sequence". 11 | 12 | We represent a DNA sequence as an ordered collection of these four nucleotides and a common way to do that is with a string of characters such as "ATTACG" for a DNA sequence of 6 nucleotides. 13 | 'A' for adenine, 'C' for cytosine, 'G' for guanine, and 'T' for thymine. 14 | 15 | Given a string representing a DNA sequence, count how many of each nucleotide is present. 16 | If the string contains characters that aren't A, C, G, or T then it is invalid and you should signal an error. 17 | 18 | For example: 19 | 20 | ```text 21 | "GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2 22 | "INVALID" -> error 23 | ``` 24 | -------------------------------------------------------------------------------- /exercises/practice/nucleotide-count/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "nucleotide-count.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a DNA string, compute how many times each nucleotide occurs in the string.", 17 | "source": "The Calculating DNA Nucleotides_problem at Rosalind", 18 | "source_url": "https://rosalind.info/problems/dna/" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/nucleotide-count/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun nucleotideCounts (strand: string): {a: int, c: int, g: int, t: int} = 2 | let 3 | fun recurse(a: int, c: int, g: int, t: int, nil) = {a = a, c = c, g = g, t = t} 4 | | recurse(a: int, c: int, g: int, t: int, hd :: tl) = 5 | case hd of 6 | #"A" => recurse(a + 1, c, g, t, tl) 7 | | #"C" => recurse(a, c + 1, g, t, tl) 8 | | #"G" => recurse(a, c, g + 1, t, tl) 9 | | #"T" => recurse(a, c, g, t + 1, tl) 10 | | _ => raise Fail "Invalid nucleotide in strand" 11 | in 12 | recurse (0, 0, 0, 0, explode strand) 13 | end 14 | -------------------------------------------------------------------------------- /exercises/practice/nucleotide-count/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [3e5c30a8-87e2-4845-a815-a49671ade970] 13 | description = "empty strand" 14 | 15 | [a0ea42a6-06d9-4ac6-828c-7ccaccf98fec] 16 | description = "can count one nucleotide in single-character input" 17 | 18 | [eca0d565-ed8c-43e7-9033-6cefbf5115b5] 19 | description = "strand with repeated nucleotide" 20 | 21 | [40a45eac-c83f-4740-901a-20b22d15a39f] 22 | description = "strand with multiple nucleotides" 23 | 24 | [b4c47851-ee9e-4b0a-be70-a86e343bd851] 25 | description = "strand with invalid nucleotides" 26 | -------------------------------------------------------------------------------- /exercises/practice/nucleotide-count/nucleotide-count.sml: -------------------------------------------------------------------------------- 1 | fun nucleotideCounts (strand: string): {a: int, c: int, g: int, t: int} = 2 | raise Fail "'nucleotideCounts' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/nucleotide-count/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "testlib.sml"; 4 | use "nucleotide-count.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "nucleotide-count" [ 11 | test "empty strand" 12 | (fn _ => nucleotideCounts "" |> Expect.equalTo {a = 0, c = 0, g = 0, t = 0}), 13 | 14 | test "can count one nucleotide in single-character input" 15 | (fn _ => nucleotideCounts "G" |> Expect.equalTo {a = 0, c = 0, g = 1, t = 0}), 16 | 17 | test "strand with repeated nucleotide" 18 | (fn _ => nucleotideCounts "GGGGGGG" |> Expect.equalTo {a = 0, c = 0, g = 7, t = 0}), 19 | 20 | test "strand with multiple nucleotides" 21 | (fn _ => nucleotideCounts "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC" |> Expect.equalTo {a = 20, c = 12, g = 17, t = 21}), 22 | 23 | test "strand with invalid nucleotides" 24 | (fn _ => (fn _ => nucleotideCounts "AGXXACT") |> Expect.error (Fail "Invalid nucleotide in strand")) 25 | ] 26 | 27 | val _ = Test.run testsuite 28 | -------------------------------------------------------------------------------- /exercises/practice/palindrome-products/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "palindrome-products.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Detect palindrome products in a given range.", 17 | "source": "Problem 4 at Project Euler", 18 | "source_url": "https://projecteuler.net/problem=4" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/palindrome-products/palindrome-products.sml: -------------------------------------------------------------------------------- 1 | fun smallest (min: int, max: int): {value: int, factors: (int * int) list} option = 2 | raise Fail "'smallest' is not implemented" 3 | 4 | fun largest (min: int, max: int): {value: int, factors: (int * int) list} option = 5 | raise Fail "'largest' is not implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to figure out if a sentence is a pangram. 4 | 5 | A pangram is a sentence using every letter of the alphabet at least once. 6 | It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). 7 | 8 | For this exercise, a sentence is a pangram if it contains each of the 26 letters in the English alphabet. 9 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a company that sells fonts through their website. 4 | They'd like to show a different sentence each time someone views a font on their website. 5 | To give a comprehensive sense of the font, the random sentences should use **all** the letters in the English alphabet. 6 | 7 | They're running a competition to get suggestions for sentences that they can use. 8 | You're in charge of checking the submissions to see if they are valid. 9 | 10 | ~~~~exercism/note 11 | Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". 12 | 13 | The best known English pangram is: 14 | 15 | > The quick brown fox jumps over the lazy dog. 16 | ~~~~ 17 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "pangram.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Determine if a sentence is a pangram.", 23 | "source": "Wikipedia", 24 | "source_url": "https://en.wikipedia.org/wiki/Pangram" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun isPangram s = 2 | let 3 | val counter = Array.tabulate (26, fn _ => 0) 4 | val chars = map Char.toLower (String.explode s) 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 19 | -------------------------------------------------------------------------------- /exercises/practice/pangram/pangram.sml: -------------------------------------------------------------------------------- 1 | fun isPangram s = 2 | raise Fail "'isPangram' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/pascals-triangle/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "rainij" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "pascals-triangle.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Compute Pascal's triangle up to a given number of rows.", 17 | "source": "Pascal's Triangle at Wolfram Math World", 18 | "source_url": "https://www.wolframalpha.com/input/?i=Pascal%27s+triangle" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/pascals-triangle/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun next row = ListPair.map (fn (a, b) => a + b) (0 :: row, row @ [0]) 2 | 3 | fun rows_impl 0 rows = rows 4 | | rows_impl c [] = rows_impl (c - 1) [[1]] 5 | | rows_impl c (r :: rows) = rows_impl (c - 1) ((next r) :: r :: rows) 6 | 7 | fun rows (count: int): int list list = List.rev (rows_impl count []) 8 | -------------------------------------------------------------------------------- /exercises/practice/pascals-triangle/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [9920ce55-9629-46d5-85d6-4201f4a4234d] 13 | description = "zero rows" 14 | 15 | [70d643ce-a46d-4e93-af58-12d88dd01f21] 16 | description = "single row" 17 | 18 | [a6e5a2a2-fc9a-4b47-9f4f-ed9ad9fbe4bd] 19 | description = "two rows" 20 | 21 | [97206a99-79ba-4b04-b1c5-3c0fa1e16925] 22 | description = "three rows" 23 | 24 | [565a0431-c797-417c-a2c8-2935e01ce306] 25 | description = "four rows" 26 | 27 | [06f9ea50-9f51-4eb2-b9a9-c00975686c27] 28 | description = "five rows" 29 | 30 | [c3912965-ddb4-46a9-848e-3363e6b00b13] 31 | description = "six rows" 32 | 33 | [6cb26c66-7b57-4161-962c-81ec8c99f16b] 34 | description = "ten rows" 35 | -------------------------------------------------------------------------------- /exercises/practice/pascals-triangle/pascals-triangle.sml: -------------------------------------------------------------------------------- 1 | fun rows (count: int): int list list = 2 | raise Fail "'rows' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/pascals-triangle/test.sml: -------------------------------------------------------------------------------- 1 | use "testlib.sml"; 2 | use "pascals-triangle.sml"; 3 | 4 | infixr |> 5 | fun x |> f = f x 6 | 7 | val testsuite = 8 | describe "pascals-triangle" [ 9 | test "zero rows" 10 | (fn _ => rows 0 |> Expect.equalTo []), 11 | 12 | test "single row" 13 | (fn _ => rows 1 |> Expect.equalTo [[1]]), 14 | 15 | test "two rows" 16 | (fn _ => rows 2 |> Expect.equalTo [[1], [1, 1]]), 17 | 18 | test "three rows" 19 | (fn _ => rows 3 |> Expect.equalTo [[1], [1, 1], [1, 2, 1]]), 20 | 21 | test "four rows" 22 | (fn _ => rows 4 |> Expect.equalTo [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]]), 23 | 24 | test "five rows" 25 | (fn _ => rows 5 |> Expect.equalTo [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]), 26 | 27 | test "six rows" 28 | (fn _ => rows 6 |> Expect.equalTo [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]), 29 | 30 | test "ten rows" 31 | (fn _ => rows 10 |> Expect.equalTo [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1], [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]]) 32 | ] 33 | 34 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "perfect-numbers.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.", 23 | "source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.", 24 | "source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/.meta/example.sml: -------------------------------------------------------------------------------- 1 | datatype classification = Deficient | Perfect | Abundant 2 | 3 | (* Divisors come in pairs (i,j) with i <= sqrt n. *) 4 | (* When i = sqrt n, count this divisor once. *) 5 | fun properDivisors 1 = [] 6 | | properDivisors n = 7 | let fun loop i = 8 | if i * i > n 9 | then [] 10 | else if n mod i <> 0 11 | then loop (i+1) 12 | else if i * i = n 13 | then i :: loop (i+1) 14 | else i :: n div i :: loop (i+1) 15 | in 1 :: loop 2 end 16 | 17 | val sum = foldl op+ 0 18 | 19 | fun classify n = 20 | if n < 1 21 | then NONE 22 | else SOME (case Int.compare (n, sum (properDivisors n)) of 23 | LESS => Abundant 24 | | EQUAL => Perfect 25 | | GREATER => Deficient) 26 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/perfect-numbers.sml: -------------------------------------------------------------------------------- 1 | datatype classification = Abundant | Deficient | Perfect 2 | 3 | fun classify (input: int): classification option = 4 | raise Fail "'classify' is not implemented" 5 | -------------------------------------------------------------------------------- /exercises/practice/phone-number/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You've joined LinkLine, a leading communications company working to ensure reliable connections for everyone. 4 | The team faces a big challenge: users submit phone numbers in all sorts of formats — dashes, spaces, dots, parentheses, and even prefixes. 5 | Some numbers are valid, while others are impossible to use. 6 | 7 | Your mission is to turn this chaos into order. 8 | You'll clean up valid numbers, formatting them appropriately for use in the system. 9 | At the same time, you'll identify and filter out any invalid entries. 10 | 11 | The success of LinkLine's operations depends on your ability to separate the useful from the unusable. 12 | Are you ready to take on the challenge and keep the connections running smoothly? 13 | -------------------------------------------------------------------------------- /exercises/practice/phone-number/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "phone-number.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Clean up user-entered phone numbers so that they can be sent SMS messages.", 23 | "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", 24 | "source_url": "https://turing.edu" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/phone-number/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun clean text = 2 | let 3 | fun valid (#"0" :: _) = false 4 | | valid (#"1" :: _) = false 5 | | valid digits = List.nth (digits, 3) > #"1" 6 | 7 | fun check digits = 8 | case length digits of 9 | 10 => if valid digits 10 | then SOME (implode digits) 11 | else NONE 12 | | 11 => if hd digits = #"1" 13 | then check (tl digits) 14 | else NONE 15 | | _ => NONE 16 | in 17 | check (List.filter Char.isDigit (explode text)) 18 | end 19 | -------------------------------------------------------------------------------- /exercises/practice/phone-number/phone-number.sml: -------------------------------------------------------------------------------- 1 | fun clean (text: string): string option = 2 | raise Fail "'clean' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/pig-latin/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Your parents have challenged you and your sibling to a game of two-on-two basketball. 4 | Confident they'll win, they let you score the first couple of points, but then start taking over the game. 5 | Needing a little boost, you start speaking in [Pig Latin][pig-latin], which is a made-up children's language that's difficult for non-children to understand. 6 | This will give you the edge to prevail over your parents! 7 | 8 | [pig-latin]: https://en.wikipedia.org/wiki/Pig_latin 9 | -------------------------------------------------------------------------------- /exercises/practice/pig-latin/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "pig-latin.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Implement a program that translates from English to Pig Latin.", 23 | "source": "The Pig Latin exercise at Test First Teaching by Ultrasaurus", 24 | "source_url": "https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/pig-latin/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun isVowelCluster #"a" _ = true 2 | | isVowelCluster #"e" _ = true 3 | | isVowelCluster #"i" _ = true 4 | | isVowelCluster #"o" _ = true 5 | | isVowelCluster #"u" _ = true 6 | | isVowelCluster #"y" #"t" = true 7 | | isVowelCluster #"x" #"r" = true 8 | | isVowelCluster _ _ = false 9 | 10 | fun isCluster #"q" #"u" = true 11 | | isCluster _ _ = false 12 | 13 | fun translate' [] = "" 14 | | translate' [x] = Char.toString x ^ "ay" 15 | | translate' [#"m", #"y"] = "ymay" 16 | | translate' (word as (a::b::cs)) = 17 | if isVowelCluster a b 18 | then implode word ^ "ay" 19 | else if isCluster a b 20 | then translate' (cs @ [a, b]) 21 | else translate' (b :: cs @ [a]) 22 | 23 | fun translate words = String.concatWith " " (map (translate' o explode) (String.tokens Char.isSpace words)) 24 | -------------------------------------------------------------------------------- /exercises/practice/pig-latin/pig-latin.sml: -------------------------------------------------------------------------------- 1 | fun translate (input: string): string = 2 | raise Fail "'translate' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/prime-factors/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 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. 14 | 2 goes into 60, leaving 30. 15 | - 2 goes into 30, leaving 15. 16 | - 2 doesn't go cleanly into 15. 17 | So let's move on to our next divisor, 3. 18 | - 3 goes cleanly into 15, leaving 5. 19 | - 3 does not go cleanly into 5. 20 | The next possible factor is 4. 21 | - 4 does not go cleanly into 5. 22 | The next possible factor is 5. 23 | - 5 does go cleanly into 5. 24 | - We're left only with 1, so now, we're done. 25 | 26 | Our successful divisors in that computation represent the list of prime factors of 60: 2, 2, 3, and 5. 27 | 28 | You can check this yourself: 29 | 30 | ```text 31 | 2 * 2 * 3 * 5 32 | = 4 * 15 33 | = 60 34 | ``` 35 | 36 | Success! 37 | -------------------------------------------------------------------------------- /exercises/practice/prime-factors/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "prime-factors.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Compute the prime factors of a given natural number.", 23 | "source": "The Prime Factors Kata by Uncle Bob", 24 | "source_url": "https://web.archive.org/web/20221026171801/http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/prime-factors/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun primeFactors 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 16 | -------------------------------------------------------------------------------- /exercises/practice/prime-factors/prime-factors.sml: -------------------------------------------------------------------------------- 1 | fun primeFactors n = 2 | raise Fail "'primeFactors' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/prime-factors/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.1.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 _ => primeFactors (1) |> Expect.equalTo []), 14 | 15 | test "prime number" 16 | (fn _ => primeFactors (2) |> Expect.equalTo [2]), 17 | 18 | test "square of a prime" 19 | (fn _ => primeFactors (9) |> Expect.equalTo [3, 3]), 20 | 21 | test "cube of a prime" 22 | (fn _ => primeFactors (8) |> Expect.equalTo [2, 2, 2]), 23 | 24 | test "product of primes and non-primes" 25 | (fn _ => primeFactors (12) |> Expect.equalTo [2, 2, 3]), 26 | 27 | test "product of primes" 28 | (fn _ => primeFactors (901255) |> Expect.equalTo [5, 17, 23, 461]), 29 | 30 | test "factors include a large prime" 31 | (fn _ => primeFactors (93819012551) |> Expect.equalTo [11, 9539, 894119]) 32 | ] 33 | ] 34 | 35 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/protein-translation/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "protein-translation.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Translate RNA sequences into proteins.", 17 | "source": "Tyler Long" 18 | } 19 | -------------------------------------------------------------------------------- /exercises/practice/protein-translation/protein-translation.sml: -------------------------------------------------------------------------------- 1 | fun proteins (strand: string): string list = 2 | raise Fail "'proteins' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/proverb/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | For want of a horseshoe nail, a kingdom was lost, or so the saying goes. 4 | 5 | Given a list of inputs, generate the relevant proverb. 6 | For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme: 7 | 8 | ```text 9 | For want of a nail the shoe was lost. 10 | For want of a shoe the horse was lost. 11 | For want of a horse the rider was lost. 12 | For want of a rider the message was lost. 13 | For want of a message the battle was lost. 14 | For want of a battle the kingdom was lost. 15 | And all for the want of a nail. 16 | ``` 17 | 18 | Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. 19 | No line of the output text should be a static, unchanging string; all should vary according to the input given. 20 | -------------------------------------------------------------------------------- /exercises/practice/proverb/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "proverb.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "For want of a horseshoe nail, a kingdom was lost, or so the saying goes. Output the full text of this proverbial rhyme.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/For_Want_of_a_Nail" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/proverb/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | fun recurse (previous: string, inputs: string list): string = 3 | case inputs of 4 | nil => "" 5 | | current :: rest => "For want of a " ^ previous ^ " the " ^ current ^ " was lost.\n" ^ (recurse (current, rest)) 6 | in 7 | fun recite nil = "" 8 | | recite (first :: rest) = (recurse (first, rest)) ^ "And all for the want of a " ^ first ^ "." 9 | end 10 | -------------------------------------------------------------------------------- /exercises/practice/proverb/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [e974b73e-7851-484f-8d6d-92e07fe742fc] 13 | description = "zero pieces" 14 | 15 | [2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4] 16 | description = "one piece" 17 | 18 | [d9d0a8a1-d933-46e2-aa94-eecf679f4b0e] 19 | description = "two pieces" 20 | 21 | [c95ef757-5e94-4f0d-a6cb-d2083f5e5a83] 22 | description = "three pieces" 23 | 24 | [433fb91c-35a2-4d41-aeab-4de1e82b2126] 25 | description = "full proverb" 26 | 27 | [c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7] 28 | description = "four pieces modernized" 29 | -------------------------------------------------------------------------------- /exercises/practice/proverb/proverb.sml: -------------------------------------------------------------------------------- 1 | fun recite (inputs: string list): string = 2 | raise Fail "'recite' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/pythagorean-triplet/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for which, 4 | 5 | ```text 6 | a² + b² = c² 7 | ``` 8 | 9 | and such that, 10 | 11 | ```text 12 | a < b < c 13 | ``` 14 | 15 | For example, 16 | 17 | ```text 18 | 3² + 4² = 5². 19 | ``` 20 | 21 | Given an input integer N, find all Pythagorean triplets for which `a + b + c = N`. 22 | 23 | For example, with N = 1000, there is exactly one Pythagorean triplet for which `a + b + c = 1000`: `{200, 375, 425}`. 24 | -------------------------------------------------------------------------------- /exercises/practice/pythagorean-triplet/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You are an accomplished problem-solver, known for your ability to tackle the most challenging mathematical puzzles. 4 | One evening, you receive an urgent letter from an inventor called the Triangle Tinkerer, who is working on a groundbreaking new project. 5 | The letter reads: 6 | 7 | > Dear Mathematician, 8 | > 9 | > I need your help. 10 | > I am designing a device that relies on the unique properties of Pythagorean triplets — sets of three integers that satisfy the equation a² + b² = c². 11 | > This device will revolutionize navigation, but for it to work, I must program it with every possible triplet where the sum of a, b, and c equals a specific number, N. 12 | > Calculating these triplets by hand would take me years, but I hear you are more than up to the task. 13 | > 14 | > Time is of the essence. 15 | > The future of my invention — and perhaps even the future of mathematical innovation — rests on your ability to solve this problem. 16 | 17 | Motivated by the importance of the task, you set out to find all Pythagorean triplets that satisfy the condition. 18 | Your work could have far-reaching implications, unlocking new possibilities in science and engineering. 19 | Can you rise to the challenge and make history? 20 | -------------------------------------------------------------------------------- /exercises/practice/pythagorean-triplet/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "pythagorean-triplet.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given an integer N, find all Pythagorean triplets for which a + b + c = N.", 17 | "source": "A variation of Problem 9 from Project Euler", 18 | "source_url": "https://projecteuler.net/problem=9" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/pythagorean-triplet/.meta/example.sml: -------------------------------------------------------------------------------- 1 | (* For every Pythagorean triplet with total a + b + c = n, 2 | * a² + b² = c² 3 | * <=> a² + b² = (n - a - b)², substituting c 4 | * <=> 0 = n² - 2*n*a - 2*n*b + 2*a*b 5 | * <=> (2*n - 2*a) b = (n² - 2*n*a) 6 | * <=> b = (n² - 2*n*a) / (2*n - 2*a) 7 | * 8 | * The denominator is never 0, as perimeter exceeds a side length. 9 | *) 10 | fun tripletsWithSum (n: int): (int * int * int) list = 11 | let 12 | fun recurse (a: int): (int * int * int) list = 13 | let 14 | val numerator = n * (n - 2 * a) 15 | val denominator = 2 * (n - a) 16 | val b = numerator div denominator 17 | in 18 | if b <= a then nil 19 | else if numerator mod denominator <> 0 then recurse (a + 1) 20 | else (a, b, n - a - b) :: recurse (a + 1) 21 | end 22 | in 23 | if n < 2 then nil 24 | else recurse 1 25 | end 26 | -------------------------------------------------------------------------------- /exercises/practice/pythagorean-triplet/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [a19de65d-35b8-4480-b1af-371d9541e706] 13 | description = "triplets whose sum is 12" 14 | 15 | [48b21332-0a3d-43b2-9a52-90b2a6e5c9f5] 16 | description = "triplets whose sum is 108" 17 | 18 | [dffc1266-418e-4daa-81af-54c3e95c3bb5] 19 | description = "triplets whose sum is 1000" 20 | 21 | [5f86a2d4-6383-4cce-93a5-e4489e79b186] 22 | description = "no matching triplets for 1001" 23 | 24 | [bf17ba80-1596-409a-bb13-343bdb3b2904] 25 | description = "returns all matching triplets" 26 | 27 | [9d8fb5d5-6c6f-42df-9f95-d3165963ac57] 28 | description = "several matching triplets" 29 | 30 | [f5be5734-8aa0-4bd1-99a2-02adcc4402b4] 31 | description = "triplets for large number" 32 | -------------------------------------------------------------------------------- /exercises/practice/pythagorean-triplet/pythagorean-triplet.sml: -------------------------------------------------------------------------------- 1 | fun tripletsWithSum (n: int): (int * int * int) list = 2 | raise Fail "'tripletsWithSum' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other. 4 | 5 | In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal. 6 | 7 | A chessboard can be represented by an 8 by 8 array. 8 | 9 | So if you are told the white queen is at `c5` (zero-indexed at column 2, row 3) and the black queen at `f2` (zero-indexed at column 5, row 6), then you know that the set-up is like so: 10 | 11 | ![A chess board with two queens. Arrows emanating from the queen at c5 indicate possible directions of capture along file, rank and diagonal.](https://assets.exercism.org/images/exercises/queen-attack/queen-capture.svg) 12 | 13 | You are also able to answer whether the queens can attack each other. 14 | In this case, that answer would be yes, they can, because both pieces share a diagonal. 15 | 16 | ## Credit 17 | 18 | The chessboard image was made by [habere-et-dispertire][habere-et-dispertire] using LaTeX and the [chessboard package][chessboard-package] by Ulrike Fischer. 19 | 20 | [habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire 21 | [chessboard-package]: https://github.com/u-fischer/chessboard 22 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "queen-attack.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.", 17 | "source": "J Dalbey's Programming Practice problems", 18 | "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun create (row: int, column: int) = 2 | if row < 0 then raise Fail "row not positive" 3 | else if row > 7 then raise Fail "row not on board" 4 | else if column < 0 then raise Fail "column not positive" 5 | else if column > 7 then raise Fail "column not on board" 6 | else (row, column) 7 | 8 | fun canAttack whiteQueen blackQueen: bool = 9 | let 10 | val (r1, c1) = whiteQueen 11 | val (r2, c2) = blackQueen 12 | val dr = r2 - r1 13 | val dc = c2 - c1 14 | in 15 | dr = 0 orelse dc = 0 orelse dr = dc orelse dr + dc = 0 16 | end 17 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/queen-attack.sml: -------------------------------------------------------------------------------- 1 | fun create (row: int, column: int) = 2 | raise Fail "'create' is not implemented" 3 | 4 | fun canAttack whiteQueen blackQueen: bool = 5 | raise Fail "'canAttack' is not implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to convert a number into its corresponding raindrop sounds. 4 | 5 | If a given number: 6 | 7 | - is divisible by 3, add "Pling" to the result. 8 | - is divisible by 5, add "Plang" to the result. 9 | - is divisible by 7, add "Plong" to the result. 10 | - **is not** divisible by 3, 5, or 7, the result should be the number as a string. 11 | 12 | ## Examples 13 | 14 | - 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. 15 | - 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. 16 | - 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. 17 | 18 | ~~~~exercism/note 19 | A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. 20 | Most languages provide operators or functions for one (or both) of these. 21 | 22 | [remainder]: https://exercism.org/docs/programming/operators/remainder 23 | [modulo]: https://en.wikipedia.org/wiki/Modulo_operation 24 | ~~~~ 25 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. 4 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "hanjiexi", 7 | "iHiD", 8 | "kytrinyx", 9 | "mcmillhj-wta", 10 | "sjwarner-bp", 11 | "sshine" 12 | ], 13 | "files": { 14 | "solution": [ 15 | "raindrops.sml" 16 | ], 17 | "test": [ 18 | "test.sml" 19 | ], 20 | "example": [ 21 | ".meta/example.sml" 22 | ] 23 | }, 24 | "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", 25 | "source": "A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division.", 26 | "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" 27 | } 28 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun convert n = 2 | let 3 | fun sound (i, s) = if n mod i = 0 then s else "" 4 | val sounds = [ 5 | (3, "Pling"), 6 | (5, "Plang"), 7 | (7, "Plong") 8 | ] 9 | in 10 | case String.concat (List.map sound sounds) of 11 | "" => Int.toString n 12 | | s => s 13 | end 14 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/raindrops.sml: -------------------------------------------------------------------------------- 1 | fun convert n = 2 | raise Fail "'convert' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color-duo/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "resistor-color-duo.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Convert color codes, as used on resistors, to a numeric value.", 17 | "source": "Maud de Vries, Erik Schierboom", 18 | "source_url": "https://github.com/exercism/problem-specifications/issues/1464" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color-duo/.meta/example.sml: -------------------------------------------------------------------------------- 1 | val colors = 2 | ["black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white"] 3 | 4 | fun colorCode (color: string) = 5 | let 6 | fun recurse (l: string list, index: int): int = 7 | case l of 8 | nil => raise Fail "invalid color" 9 | | first :: rest => 10 | if first = color then index 11 | else recurse (rest, index + 1) 12 | in 13 | recurse (colors, 0) 14 | end 15 | 16 | fun value (colors: string list): int = 17 | case colors of 18 | first :: second :: rest => 19 | 10 * (colorCode first) + (colorCode second) 20 | | _ => raise Fail "insufficient colors" 21 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color-duo/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [ce11995a-5b93-4950-a5e9-93423693b2fc] 13 | description = "Brown and black" 14 | 15 | [7bf82f7a-af23-48ba-a97d-38d59406a920] 16 | description = "Blue and grey" 17 | 18 | [f1886361-fdfd-4693-acf8-46726fe24e0c] 19 | description = "Yellow and violet" 20 | 21 | [b7a6cbd2-ae3c-470a-93eb-56670b305640] 22 | description = "White and red" 23 | 24 | [77a8293d-2a83-4016-b1af-991acc12b9fe] 25 | description = "Orange and orange" 26 | 27 | [0c4fb44f-db7c-4d03-afa8-054350f156a8] 28 | description = "Ignore additional colors" 29 | 30 | [4a8ceec5-0ab4-4904-88a4-daf953a5e818] 31 | description = "Black and brown, one-digit" 32 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color-duo/resistor-color-duo.sml: -------------------------------------------------------------------------------- 1 | fun value (colors: string list): int = 2 | raise Fail "'value' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/resistor-color-duo/test.sml: -------------------------------------------------------------------------------- 1 | use "testlib.sml"; 2 | use "resistor-color-duo.sml"; 3 | 4 | infixr |> 5 | fun x |> f = f x 6 | 7 | val testsuite = 8 | describe "resistor-color-duo" [ 9 | test "Brown and black" 10 | (fn _ => value ["brown", "black"] |> Expect.equalTo 10), 11 | 12 | test "Blue and grey" 13 | (fn _ => value ["blue", "grey"] |> Expect.equalTo 68), 14 | 15 | test "Yellow and violet" 16 | (fn _ => value ["yellow", "violet"] |> Expect.equalTo 47), 17 | 18 | test "White and red" 19 | (fn _ => value ["white", "red"] |> Expect.equalTo 92), 20 | 21 | test "Orange and orange" 22 | (fn _ => value ["orange", "orange"] |> Expect.equalTo 33), 23 | 24 | test "Ignore additional colors" 25 | (fn _ => value ["green", "brown", "orange"] |> Expect.equalTo 51), 26 | 27 | test "Black and brown, one-digit" 28 | (fn _ => value ["black", "brown"] |> Expect.equalTo 1) 29 | ] 30 | 31 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/resistor-color/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "resistor-color.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Convert a resistor band's color to its numeric representation.", 17 | "source": "Maud de Vries, Erik Schierboom", 18 | "source_url": "https://github.com/exercism/problem-specifications/issues/1458" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color/.meta/example.sml: -------------------------------------------------------------------------------- 1 | val colors = 2 | ["black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white"] 3 | 4 | fun colorCode (color: string) = 5 | let 6 | fun recurse (l: string list, index: int): int = 7 | case l of 8 | nil => raise Fail "invalid color" 9 | | first :: rest => 10 | if first = color then index 11 | else recurse (rest, index + 1) 12 | in 13 | recurse (colors, 0) 14 | end 15 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [49eb31c5-10a8-4180-9f7f-fea632ab87ef] 13 | description = "Color codes -> Black" 14 | 15 | [0a4df94b-92da-4579-a907-65040ce0b3fc] 16 | description = "Color codes -> White" 17 | 18 | [5f81608d-f36f-4190-8084-f45116b6f380] 19 | description = "Color codes -> Orange" 20 | 21 | [581d68fa-f968-4be2-9f9d-880f2fb73cf7] 22 | description = "Colors" 23 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color/resistor-color.sml: -------------------------------------------------------------------------------- 1 | fun colorCode color = 2 | raise Fail "'colorCode' is not implemented" 3 | 4 | val colors: string list = 5 | nil 6 | -------------------------------------------------------------------------------- /exercises/practice/resistor-color/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "testlib.sml"; 4 | use "resistor-color.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "resistor-color" [ 11 | describe "Color codes" [ 12 | test "Black" 13 | (fn _ => colorCode "black" |> Expect.equalTo 0), 14 | 15 | test "White" 16 | (fn _ => colorCode "white" |> Expect.equalTo 9), 17 | 18 | test "Orange" 19 | (fn _ => colorCode "orange" |> Expect.equalTo 3) 20 | ], 21 | 22 | test "Colors" 23 | (fn _ => let 24 | val expected = ["black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white"] 25 | in 26 | colors |> Expect.equalTo expected 27 | end) 28 | ] 29 | 30 | val _ = Test.run testsuite 31 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to reverse a given string. 4 | 5 | Some examples: 6 | 7 | - Turn `"stressed"` into `"desserts"`. 8 | - Turn `"strops"` into `"sports"`. 9 | - Turn `"racecar"` into `"racecar"`. 10 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Reversing strings (reading them from right to left, rather than from left to right) is a surprisingly common task in programming. 4 | 5 | For example, in bioinformatics, reversing the sequence of DNA or RNA strings is often important for various analyses, such as finding complementary strands or identifying palindromic sequences that have biological significance. 6 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "rainij" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "reverse-string.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Reverse a given string.", 17 | "source": "Introductory challenge to reverse an input string", 18 | "source_url": "https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun reverse (value: string): string = 2 | let 3 | fun shovel ([], rs) = rs 4 | | shovel (x :: xs, rs) = shovel (xs, x :: rs) 5 | 6 | fun list_reverse xs = shovel (xs, []) 7 | in 8 | String.implode (list_reverse (String.explode value)) 9 | end; 10 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/reverse-string.sml: -------------------------------------------------------------------------------- 1 | fun reverse (value: string): string = 2 | raise Fail "'reverse' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/test.sml: -------------------------------------------------------------------------------- 1 | use "testlib.sml"; 2 | use "reverse-string.sml"; 3 | 4 | infixr |> 5 | fun x |> f = f x 6 | 7 | val testsuite = 8 | describe "reverse-string" [ 9 | test "an empty string" 10 | (fn _ => reverse "" |> Expect.equalTo ""), 11 | 12 | test "a word" 13 | (fn _ => reverse "robot" |> Expect.equalTo "tobor"), 14 | 15 | test "a capitalized word" 16 | (fn _ => reverse "Ramen" |> Expect.equalTo "nemaR"), 17 | 18 | test "a sentence with punctuation" 19 | (fn _ => reverse "I'm hungry!" |> Expect.equalTo "!yrgnuh m'I"), 20 | 21 | test "a palindrome" 22 | (fn _ => reverse "racecar" |> Expect.equalTo "racecar"), 23 | 24 | test "an even-sized word" 25 | (fn _ => reverse "drawer" |> Expect.equalTo "reward") 26 | ] 27 | 28 | val _ = Test.run testsuite 29 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine the RNA complement of a given DNA sequence. 4 | 5 | Both DNA and RNA strands are a sequence of nucleotides. 6 | 7 | The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**), and thymine (**T**). 8 | 9 | The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**), and uracil (**U**). 10 | 11 | Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement: 12 | 13 | - `G` -> `C` 14 | - `C` -> `G` 15 | - `T` -> `A` 16 | - `A` -> `U` 17 | 18 | ~~~~exercism/note 19 | If you want to look at how the inputs and outputs are structured, take a look at the examples in the test suite. 20 | ~~~~ 21 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a bioengineering company that specializes in developing therapeutic solutions. 4 | 5 | Your team has just been given a new project to develop a targeted therapy for a rare type of cancer. 6 | 7 | ~~~~exercism/note 8 | It's all very complicated, but the basic idea is that sometimes people's bodies produce too much of a given protein. 9 | That can cause all sorts of havoc. 10 | 11 | But if you can create a very specific molecule (called a micro-RNA), it can prevent the protein from being produced. 12 | 13 | This technique is called [RNA Interference][rnai]. 14 | 15 | [rnai]: https://admin.acceleratingscience.com/ask-a-scientist/what-is-rnai/ 16 | ~~~~ 17 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "rna-transcription.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Given a DNA strand, return its RNA complement.", 23 | "source": "Hyperphysics", 24 | "source_url": "https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun toRna dna = 2 | let 3 | fun translate #"G" = SOME #"C" 4 | | translate #"C" = SOME #"G" 5 | | translate #"T" = SOME #"A" 6 | | translate #"A" = SOME #"U" 7 | | translate _ = NONE 8 | 9 | fun reducer (_, NONE) = NONE 10 | | reducer (x, SOME acc) = 11 | let 12 | val t = translate x 13 | in 14 | case t of 15 | NONE => NONE 16 | | SOME c => SOME (c :: acc) 17 | end 18 | in 19 | Option.map implode (foldr reducer (SOME []) (explode dna)) 20 | end 21 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [b4631f82-c98c-4a2f-90b3-c5c2b6c6f661] 13 | description = "Empty RNA sequence" 14 | 15 | [a9558a3c-318c-4240-9256-5d5ed47005a6] 16 | description = "RNA complement of cytosine is guanine" 17 | 18 | [6eedbb5c-12cb-4c8b-9f51-f8320b4dc2e7] 19 | description = "RNA complement of guanine is cytosine" 20 | 21 | [870bd3ec-8487-471d-8d9a-a25046488d3e] 22 | description = "RNA complement of thymine is adenine" 23 | 24 | [aade8964-02e1-4073-872f-42d3ffd74c5f] 25 | description = "RNA complement of adenine is uracil" 26 | 27 | [79ed2757-f018-4f47-a1d7-34a559392dbf] 28 | description = "RNA complement" 29 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/rna-transcription.sml: -------------------------------------------------------------------------------- 1 | fun toRna (dna: string): string option = 2 | raise Fail "'toRna' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.1 *) 2 | 3 | use "testlib.sml"; 4 | use "rna-transcription.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "rna-transcription" [ 11 | test "RNA complement of cytosine is guanine" 12 | (fn _ => toRna ("C") |> Expect.equalTo (SOME "G")), 13 | 14 | test "RNA complement of guanine is cytosine" 15 | (fn _ => toRna ("G") |> Expect.equalTo (SOME "C")), 16 | 17 | test "RNA complement of thymine is adenine" 18 | (fn _ => toRna ("T") |> Expect.equalTo (SOME "A")), 19 | 20 | test "RNA complement of adenine is uracil" 21 | (fn _ => toRna ("A") |> Expect.equalTo (SOME "U")), 22 | 23 | test "RNA complement" 24 | (fn _ => toRna ("ACGTGGTCTTAA") |> Expect.equalTo (SOME "UGCACCAGAAUU")), 25 | 26 | test "correctly handles invalid input (RNA instead of DNA)" 27 | (fn _ => toRna ("U") |> Expect.equalTo NONE), 28 | 29 | test "correctly handles completely invalid DNA input" 30 | (fn _ => toRna ("XXX") |> Expect.equalTo NONE), 31 | 32 | test "correctly handles partially invalid DNA input" 33 | (fn _ => toRna ("ACGTXXXCTTAA") |> Expect.equalTo NONE) 34 | ] 35 | 36 | val _ = Test.run testsuite -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Your task is to convert a number from Arabic numerals to Roman numerals. 4 | 5 | For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999). 6 | 7 | ~~~~exercism/note 8 | There are lots of different ways to convert between Arabic and Roman numerals. 9 | We recommend taking a naive approach first to familiarise yourself with the concept of Roman numerals and then search for more efficient methods. 10 | 11 | Make sure to check out our Deep Dive video at the end to explore the different approaches you can take! 12 | ~~~~ 13 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "roman-numerals.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Convert modern Arabic numbers into Roman numerals.", 23 | "source": "The Roman Numeral Kata", 24 | "source_url": "https://codingdojo.org/kata/RomanNumerals/" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun roman number = 2 | let 3 | val pairs = [ 4 | (1000, "M"), 5 | (900 , "CM"), 6 | (500 , "D"), 7 | (400 , "CD"), 8 | (100 , "C"), 9 | (90 , "XC"), 10 | (50 , "L"), 11 | (40 , "XL"), 12 | (10 , "X"), 13 | (9 , "IX"), 14 | (5 , "V"), 15 | (4 , "IV"), 16 | (1 , "I") 17 | ] 18 | 19 | fun loop 0 _ = [] 20 | | loop _ [] = [] 21 | | loop n (ps as ((num, rep) :: ps')) = 22 | if n < num 23 | then loop n ps' 24 | else rep :: loop (n - num) ps 25 | in 26 | concat (loop number pairs) 27 | end 28 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/roman-numerals.sml: -------------------------------------------------------------------------------- 1 | fun roman (number: int): string = 2 | raise Fail "'roman' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/rotational-cipher/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "rotational-cipher.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Caesar_cipher" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/rotational-cipher/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun rotate (shiftKey: int): string -> string = 2 | let 3 | val A = ord #"A" 4 | val a = ord #"a" 5 | 6 | fun rotateChar (ch: char): char = 7 | if ch >= #"A" andalso ch <= #"Z" then chr((shiftKey - A + ord ch) mod 26 + A) 8 | else if ch >= #"a" andalso ch <= #"z" then chr((shiftKey - a + ord ch) mod 26 + a) 9 | else ch 10 | in 11 | String.map rotateChar 12 | end 13 | -------------------------------------------------------------------------------- /exercises/practice/rotational-cipher/rotational-cipher.sml: -------------------------------------------------------------------------------- 1 | fun rotate (shiftKey: int) (text: string): string = 2 | raise Fail "'rotate' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/run-length-encoding/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Implement run-length encoding and decoding. 4 | 5 | Run-length encoding (RLE) is a simple form of data compression, where runs (consecutive data elements) are replaced by just one data value and count. 6 | 7 | For example we can represent the original 53 characters with only 13. 8 | 9 | ```text 10 | "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB" -> "12WB12W3B24WB" 11 | ``` 12 | 13 | RLE allows the original data to be perfectly reconstructed from the compressed data, which makes it a lossless data compression. 14 | 15 | ```text 16 | "AABCCCDEEEE" -> "2AB3CD4E" -> "AABCCCDEEEE" 17 | ``` 18 | 19 | For simplicity, you can assume that the unencoded string will only contain the letters A through Z (either lower or upper case) and whitespace. 20 | This way data to be encoded will never contain any numbers and numbers inside data to be decoded always represent the count for the following character. 21 | -------------------------------------------------------------------------------- /exercises/practice/run-length-encoding/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "run-length-encoding.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Implement run-length encoding and decoding.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Run-length_encoding" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/run-length-encoding/.meta/example.sml: -------------------------------------------------------------------------------- 1 | local 2 | fun repeat 0 (ch: char): char list = nil 3 | | repeat (n: int) (ch: char): char list = ch :: repeat (n - 1) ch 4 | 5 | fun uncompress (n: int) (nil: char list) = nil 6 | | uncompress (n: int) (hd :: tl): char list = 7 | if Char.isDigit hd then uncompress (n * 10 + ord hd - ord #"0") tl 8 | else if n = 0 then hd :: uncompress 0 tl 9 | else repeat n hd @ uncompress 0 tl 10 | in 11 | val decode: string -> string = 12 | implode o uncompress 0 o explode 13 | end 14 | 15 | local 16 | fun encodeRun (n: int, ch: char): char list = 17 | if n = 1 then [ch] 18 | else explode (Int.toString n) @ [ch] 19 | 20 | fun compress (n: int, ch: char) (nil: char list) = 21 | encodeRun (n, ch) 22 | | compress (n: int, ch: char) (hd :: tl): char list = 23 | if ch = hd then compress (n + 1, ch) tl 24 | else encodeRun (n, ch) @ compress (1, hd) tl 25 | in 26 | fun encode (phrase: string): string = 27 | if size phrase = 0 then phrase 28 | else (implode o compress (0, String.sub(phrase, 0)) o explode) phrase 29 | end 30 | -------------------------------------------------------------------------------- /exercises/practice/run-length-encoding/run-length-encoding.sml: -------------------------------------------------------------------------------- 1 | fun decode (phrase: string): string = 2 | raise Fail "'decode' is not implemented" 3 | 4 | fun encode (phrase: string): string = 5 | raise Fail "'encode' is not implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/say/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "say.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.", 17 | "source": "A variation on the JavaRanch CattleDrive, Assignment 4", 18 | "source_url": "https://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/say/say.sml: -------------------------------------------------------------------------------- 1 | fun say (number: int): string = 2 | raise Fail "'say' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/scrabble-score/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to compute a word's Scrabble score by summing the values of its letters. 4 | 5 | The letters are valued as follows: 6 | 7 | | Letter | Value | 8 | | ---------------------------- | ----- | 9 | | A, E, I, O, U, L, N, R, S, T | 1 | 10 | | D, G | 2 | 11 | | B, C, M, P | 3 | 12 | | F, H, V, W, Y | 4 | 13 | | K | 5 | 14 | | J, X | 8 | 15 | | Q, Z | 10 | 16 | 17 | For example, the word "cabbage" is worth 14 points: 18 | 19 | - 3 points for C 20 | - 1 point for A 21 | - 3 points for B 22 | - 3 points for B 23 | - 1 point for A 24 | - 2 points for G 25 | - 1 point for E 26 | -------------------------------------------------------------------------------- /exercises/practice/scrabble-score/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [Scrabble][wikipedia] is a word game where players place letter tiles on a board to form words. 4 | Each letter has a value. 5 | A word's score is the sum of its letters' values. 6 | 7 | [wikipedia]: https://en.wikipedia.org/wiki/Scrabble 8 | -------------------------------------------------------------------------------- /exercises/practice/scrabble-score/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "scrabble-score.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a word, compute the Scrabble score for that word.", 17 | "source": "Inspired by the Extreme Startup game", 18 | "source_url": "https://github.com/rchatley/extreme_startup" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/scrabble-score/.meta/example.sml: -------------------------------------------------------------------------------- 1 | val score: string -> int = 2 | let 3 | fun letterValue (c: char): int = 4 | case c of 5 | #"A" => 1 6 | | #"E" => 1 7 | | #"I" => 1 8 | | #"O" => 1 9 | | #"U" => 1 10 | | #"L" => 1 11 | | #"N" => 1 12 | | #"R" => 1 13 | | #"S" => 1 14 | | #"T" => 1 15 | | #"D" => 2 16 | | #"G" => 2 17 | | #"B" => 3 18 | | #"C" => 3 19 | | #"M" => 3 20 | | #"P" => 3 21 | | #"F" => 4 22 | | #"H" => 4 23 | | #"V" => 4 24 | | #"W" => 4 25 | | #"Y" => 4 26 | | #"K" => 5 27 | | #"J" => 8 28 | | #"X" => 8 29 | | #"Q" => 10 30 | | #"Z" => 10 31 | | _ => 0 32 | val sum: int list -> int = List.foldl (op +) 0 33 | in 34 | sum o List.map (letterValue o Char.toUpper) o String.explode 35 | end 36 | -------------------------------------------------------------------------------- /exercises/practice/scrabble-score/scrabble-score.sml: -------------------------------------------------------------------------------- 1 | fun score word = 2 | raise Fail "'score' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/scrabble-score/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "testlib.sml"; 4 | use "scrabble-score.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "scrabble-score" [ 11 | test "lowercase letter" 12 | (fn _ => score "a" |> Expect.equalTo 1), 13 | 14 | test "uppercase letter" 15 | (fn _ => score "A" |> Expect.equalTo 1), 16 | 17 | test "valuable letter" 18 | (fn _ => score "f" |> Expect.equalTo 4), 19 | 20 | test "short word" 21 | (fn _ => score "at" |> Expect.equalTo 2), 22 | 23 | test "short, valuable word" 24 | (fn _ => score "zoo" |> Expect.equalTo 12), 25 | 26 | test "medium word" 27 | (fn _ => score "street" |> Expect.equalTo 6), 28 | 29 | test "medium, valuable word" 30 | (fn _ => score "quirky" |> Expect.equalTo 22), 31 | 32 | test "long, mixed-case word" 33 | (fn _ => score "OxyphenButazone" |> Expect.equalTo 41), 34 | 35 | test "english-like word" 36 | (fn _ => score "pinata" |> Expect.equalTo 8), 37 | 38 | test "empty input" 39 | (fn _ => score "" |> Expect.equalTo 0), 40 | 41 | test "entire alphabet available" 42 | (fn _ => score "abcdefghijklmnopqrstuvwxyz" |> Expect.equalTo 87) 43 | ] 44 | 45 | val _ = Test.run testsuite 46 | -------------------------------------------------------------------------------- /exercises/practice/secret-handshake/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You are starting a secret coding club with some friends and friends-of-friends. 4 | Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member. 5 | You don't want anyone who isn't in the know to be able to crack the code. 6 | 7 | You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions. 8 | -------------------------------------------------------------------------------- /exercises/practice/secret-handshake/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "secret-handshake.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.", 17 | "source": "Bert, in Mary Poppins", 18 | "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/secret-handshake/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun commands (number: int): string list = 2 | let 3 | val wink = 0x1 4 | val doubleBlink = 0x2 5 | val closeYourEyes = 0x4 6 | val jump = 0x8 7 | val reverse = 0x10 8 | 9 | fun isChosen (action: int): bool = 10 | Word.andb (Word.fromInt number, Word.fromInt action) <> Word.fromInt 0 11 | 12 | fun conditionallyPrefix (action: int, command: string) (l: string list): string list = 13 | if isChosen action then command :: l 14 | else l 15 | 16 | val conditionallyWink: string list -> string list = 17 | conditionallyPrefix (wink, "wink") 18 | 19 | val conditionallyDoubleBlink: string list -> string list = 20 | conditionallyPrefix (doubleBlink, "double blink") 21 | 22 | val conditionallyCloseYourEyes: string list -> string list = 23 | conditionallyPrefix (closeYourEyes, "close your eyes") 24 | 25 | val conditionallyJump: string list -> string list = 26 | conditionallyPrefix (jump, "jump") 27 | 28 | fun conditionallyReverse l = 29 | if isChosen reverse then rev l 30 | else l 31 | in 32 | (conditionallyReverse o conditionallyWink o conditionallyDoubleBlink o conditionallyCloseYourEyes o conditionallyJump) [] 33 | end 34 | -------------------------------------------------------------------------------- /exercises/practice/secret-handshake/secret-handshake.sml: -------------------------------------------------------------------------------- 1 | fun commands (number: int): string list = 2 | raise Fail "'commands' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You bought a big box of random computer parts at a garage sale. 4 | You've started putting the parts together to build custom computers. 5 | 6 | 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. 7 | You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits. 8 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "glennj" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "sieve.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.", 17 | "source": "Sieve of Eratosthenes at Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun primes (limit: int): int list = 2 | let val marks = Array.array (limit + 1, true) 3 | 4 | fun markMultiples prev = 5 | case Array.findi (fn (i, isPrime) => i > prev andalso isPrime) marks 6 | of NONE => () 7 | | SOME (prime, _) => (doMark prime (2 * prime); markMultiples prime) 8 | 9 | and doMark p m = 10 | if m > limit then () 11 | else (Array.update (marks, m, false); doMark p (m + p)) 12 | 13 | in Array.update (marks, 0, false); 14 | Array.update (marks, 1, false); 15 | markMultiples 1; 16 | Array.foldri 17 | (fn (i, isPrime, ps) => if isPrime then i :: ps else ps) 18 | [] 19 | marks 20 | end 21 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [88529125-c4ce-43cc-bb36-1eb4ddd7b44f] 13 | description = "no primes under two" 14 | 15 | [4afe9474-c705-4477-9923-840e1024cc2b] 16 | description = "find first prime" 17 | 18 | [974945d8-8cd9-4f00-9463-7d813c7f17b7] 19 | description = "find primes up to 10" 20 | 21 | [2e2417b7-3f3a-452a-8594-b9af08af6d82] 22 | description = "limit is prime" 23 | 24 | [92102a05-4c7c-47de-9ed0-b7d5fcd00f21] 25 | description = "find primes up to 1000" 26 | -------------------------------------------------------------------------------- /exercises/practice/sieve/sieve.sml: -------------------------------------------------------------------------------- 1 | fun primes (limit: int): int list = 2 | raise Fail "'primes' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/space-age/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sshine" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp" 9 | ], 10 | "files": { 11 | "solution": [ 12 | "space-age.sml" 13 | ], 14 | "test": [ 15 | "test.sml" 16 | ], 17 | "example": [ 18 | ".meta/example.sml" 19 | ] 20 | }, 21 | "blurb": "Given an age in seconds, calculate how old someone is in terms of a given planet's solar years.", 22 | "source": "Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial.", 23 | "source_url": "https://pine.fm/LearnToProgram/?Chapter=01" 24 | } 25 | -------------------------------------------------------------------------------- /exercises/practice/space-age/.meta/example.sml: -------------------------------------------------------------------------------- 1 | datatype planet = Mercury | Venus | Earth | Mars 2 | | Jupiter | Saturn | Uranus | Neptune 3 | 4 | fun earthYears seconds = seconds / 31557600.0 5 | 6 | fun orbitalPeriod planet = 7 | case planet of 8 | Mercury => 0.2408467 9 | | Venus => 0.61519726 10 | | Earth => 1.0 11 | | Mars => 1.8808158 12 | | Jupiter => 11.862615 13 | | Saturn => 29.447498 14 | | Uranus => 84.016846 15 | | Neptune => 164.79132 16 | 17 | fun age_on planet seconds = 18 | earthYears (Real.fromInt seconds) / orbitalPeriod planet 19 | -------------------------------------------------------------------------------- /exercises/practice/space-age/space-age.sml: -------------------------------------------------------------------------------- 1 | datatype planet = Mercury | Venus | Earth | Mars 2 | | Jupiter | Saturn | Uranus | Neptune 3 | 4 | fun age_on planet seconds = 5 | raise Fail "'age_on' is not implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/space-age/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "testlib.sml"; 4 | use "space-age.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "age_on" [ 11 | test "age on Earth" 12 | (fn _ => age_on Earth 1000000000 |> Expect.nearTo 0.005 31.69), 13 | test "age on Mercury" 14 | (fn _ => age_on Mercury 2134835688 |> Expect.nearTo 0.005 280.88), 15 | test "age on Venus" 16 | (fn _ => age_on Venus 189839836 |> Expect.nearTo 0.005 9.78), 17 | test "age on Mars" 18 | (fn _ => age_on Mars 2329871239 |> Expect.nearTo 0.005 39.25), 19 | test "age on Jupiter" 20 | (fn _ => age_on Jupiter 901876382 |> Expect.nearTo 0.005 2.41), 21 | test "age on Saturn" 22 | (fn _ => age_on Saturn 3000000000 |> Expect.nearTo 0.005 3.23), 23 | test "age on Uranus" 24 | (fn _ => age_on Uranus 3210123456 |> Expect.nearTo 0.005 1.21), 25 | test "age on Neptune" 26 | (fn _ => age_on Neptune 8210123456 |> Expect.nearTo 0.005 1.58) 27 | ] 28 | 29 | val _ = Test.run testsuite 30 | -------------------------------------------------------------------------------- /exercises/practice/square-root/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to calculate the square root of a given number. 4 | 5 | - Try to avoid using the pre-existing math libraries of your language. 6 | - As input you'll be given a positive whole number, i.e. 1, 2, 3, 4… 7 | - You are only required to handle cases where the result is a positive whole number. 8 | 9 | Some potential approaches: 10 | 11 | - Linear or binary search for a number that gives the input number when squared. 12 | - Successive approximation using Newton's or Heron's method. 13 | - Calculating one digit at a time or one bit at a time. 14 | 15 | You can check out the Wikipedia pages on [integer square root][integer-square-root] and [methods of computing square roots][computing-square-roots] to help with choosing a method of calculation. 16 | 17 | [integer-square-root]: https://en.wikipedia.org/wiki/Integer_square_root 18 | [computing-square-roots]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots 19 | -------------------------------------------------------------------------------- /exercises/practice/square-root/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | We are launching a deep space exploration rocket and we need a way to make sure the navigation system stays on target. 4 | 5 | As the first step in our calculation, we take a target number and find its square root (that is, the number that when multiplied by itself equals the target number). 6 | 7 | The journey will be very long. 8 | To make the batteries last as long as possible, we had to make our rocket's onboard computer very power efficient. 9 | Unfortunately that means that we can't rely on fancy math libraries and functions, as they use more power. 10 | Instead we want to implement our own square root calculation. 11 | -------------------------------------------------------------------------------- /exercises/practice/square-root/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "square-root.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Given a natural radicand, return its square root.", 17 | "source": "wolf99", 18 | "source_url": "https://github.com/exercism/problem-specifications/pull/1582" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/square-root/.meta/example.sml: -------------------------------------------------------------------------------- 1 | (* We use Heron's method, with rounding to the nearest natural number. 2 | * https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Heron's_method 3 | * estimate = (guess + randicand / guess) / 2 4 | * = (guess * guess + randicand) / (2 * guess) 5 | * To achieve rounding when using integer division, 6 | * we must increase the numerator by half the denominator. 7 | *) 8 | fun squareRoot (radicand: int): int = 9 | let 10 | fun recurse guess = 11 | let 12 | val estimate = (guess * (guess + 1) + radicand) div (2 * guess) 13 | in 14 | if estimate = guess then estimate 15 | else recurse estimate 16 | end 17 | in 18 | recurse 1 19 | end 20 | -------------------------------------------------------------------------------- /exercises/practice/square-root/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [9b748478-7b0a-490c-b87a-609dacf631fd] 13 | description = "root of 1" 14 | 15 | [7d3aa9ba-9ac6-4e93-a18b-2e8b477139bb] 16 | description = "root of 4" 17 | 18 | [6624aabf-3659-4ae0-a1c8-25ae7f33c6ef] 19 | description = "root of 25" 20 | 21 | [93beac69-265e-4429-abb1-94506b431f81] 22 | description = "root of 81" 23 | 24 | [fbddfeda-8c4f-4bc4-87ca-6991af35360e] 25 | description = "root of 196" 26 | 27 | [c03d0532-8368-4734-a8e0-f96a9eb7fc1d] 28 | description = "root of 65025" 29 | -------------------------------------------------------------------------------- /exercises/practice/square-root/square-root.sml: -------------------------------------------------------------------------------- 1 | fun squareRoot (radicand: int): int = 2 | raise Fail "'squareRoot' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/square-root/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.0.0 *) 2 | 3 | use "testlib.sml"; 4 | use "square-root.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "square-root" [ 11 | test "root of 1" 12 | (fn _ => squareRoot 1 |> Expect.equalTo 1), 13 | 14 | test "root of 4" 15 | (fn _ => squareRoot 4 |> Expect.equalTo 2), 16 | 17 | test "root of 25" 18 | (fn _ => squareRoot 25 |> Expect.equalTo 5), 19 | 20 | test "root of 81" 21 | (fn _ => squareRoot 81 |> Expect.equalTo 9), 22 | 23 | test "root of 196" 24 | (fn _ => squareRoot 196 |> Expect.equalTo 14), 25 | 26 | test "root of 65025" 27 | (fn _ => squareRoot 65025 |> Expect.equalTo 255) 28 | ] 29 | 30 | val _ = Test.run testsuite 31 | -------------------------------------------------------------------------------- /exercises/practice/strain/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Implement the `keep` and `discard` operation on collections. 4 | Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false. 5 | 6 | For example, given the collection of numbers: 7 | 8 | - 1, 2, 3, 4, 5 9 | 10 | And the predicate: 11 | 12 | - is the number even? 13 | 14 | Then your keep operation should produce: 15 | 16 | - 2, 4 17 | 18 | While your discard operation should produce: 19 | 20 | - 1, 3, 5 21 | 22 | Note that the union of keep and discard is all the elements. 23 | 24 | The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language. 25 | 26 | ## Restrictions 27 | 28 | Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library! 29 | Solve this one yourself using other basic tools instead. 30 | -------------------------------------------------------------------------------- /exercises/practice/strain/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "strain.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Implement the `keep` and `discard` operation on collections.", 17 | "source": "Conversation with James Edward Gray II", 18 | "source_url": "http://graysoftinc.com/" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/strain/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun keep f nil = nil 2 | | keep f (first :: rest) = 3 | let 4 | val suffix = keep f rest 5 | in 6 | if f first then first :: suffix 7 | else suffix 8 | end 9 | 10 | fun discard f nil = nil 11 | | discard f (first :: rest) = 12 | let 13 | val suffix = discard f rest 14 | in 15 | if f first then suffix 16 | else first :: suffix 17 | end 18 | -------------------------------------------------------------------------------- /exercises/practice/strain/strain.sml: -------------------------------------------------------------------------------- 1 | fun keep f l = 2 | raise Fail "'keep' is not implemented" 3 | 4 | fun discard f l = 5 | raise Fail "'discard' is not implemented" 6 | -------------------------------------------------------------------------------- /exercises/practice/sublist/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "sublist.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Write a function to determine if a list is a sublist of another list." 17 | } 18 | -------------------------------------------------------------------------------- /exercises/practice/sublist/.meta/example.sml: -------------------------------------------------------------------------------- 1 | datatype relation = 2 | Equal 3 | | Superlist 4 | | Sublist 5 | | Unequal 6 | 7 | local 8 | fun isPrefix (listOne: int list, listTwo: int list): bool = 9 | case (listOne, listTwo) of 10 | (nil, _) => true 11 | | (_, nil) => false 12 | | (firstOne :: restOne, firstTwo :: restTwo) => firstOne = firstTwo andalso isPrefix (restOne, restTwo) 13 | 14 | fun isSublist (listOne: int list, listTwo: int list): bool = 15 | isPrefix (listOne, listTwo) orelse (listTwo <> nil andalso isSublist (listOne, tl listTwo)) 16 | in 17 | fun sublist (listOne: int list, listTwo: int list): relation = 18 | if listOne = listTwo then Equal 19 | else if isSublist(listOne, listTwo) then Sublist 20 | else if isSublist(listTwo, listOne) then Superlist 21 | else Unequal 22 | end 23 | -------------------------------------------------------------------------------- /exercises/practice/sublist/sublist.sml: -------------------------------------------------------------------------------- 1 | datatype relation = 2 | Equal 3 | | Superlist 4 | | Sublist 5 | | Unequal 6 | 7 | fun sublist (listOne: int list, listTwo: int list): relation = 8 | raise Fail "'sublist' is not implemented" 9 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a company that makes an online, fantasy-survival game. 4 | 5 | When a player finishes a level, they are awarded energy points. 6 | The amount of energy awarded depends on which magical items the player found while exploring that level. 7 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [], 3 | "contributors": [ 4 | "iHiD", 5 | "mcmillhj-wta", 6 | "sjwarner-bp", 7 | "sshine" 8 | ], 9 | "files": { 10 | "solution": [ 11 | "sum-of-multiples.sml" 12 | ], 13 | "test": [ 14 | "test.sml" 15 | ], 16 | "example": [ 17 | ".meta/example.sml" 18 | ] 19 | }, 20 | "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", 21 | "source": "A variation on Problem 1 at Project Euler", 22 | "source_url": "https://projecteuler.net/problem=1" 23 | } 24 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun sum (factors: int list, limit: int): int = let 2 | val sum' = foldl (op +) 0 3 | val numbers = List.tabulate(limit - 1, fn x => x + 1) (* generate list from [1, limit - 1] *) 4 | fun any f [] = false 5 | | any f (x::xs) = f x orelse any f xs 6 | in 7 | sum' (List.filter (fn x => (any (fn f => x mod f = 0) factors)) numbers) 8 | end -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/sum-of-multiples.sml: -------------------------------------------------------------------------------- 1 | fun sum (factors: int list, limit: int): int = 2 | raise Fail "'sum' is not implemented" -------------------------------------------------------------------------------- /exercises/practice/transpose/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given an input text output it transposed. 4 | 5 | Roughly explained, the transpose of a matrix: 6 | 7 | ```text 8 | ABC 9 | DEF 10 | ``` 11 | 12 | is given by: 13 | 14 | ```text 15 | AD 16 | BE 17 | CF 18 | ``` 19 | 20 | Rows become columns and columns become rows. 21 | See [transpose][]. 22 | 23 | If the input has rows of different lengths, this is to be solved as follows: 24 | 25 | - Pad to the left with spaces. 26 | - Don't pad to the right. 27 | 28 | Therefore, transposing this matrix: 29 | 30 | ```text 31 | ABC 32 | DE 33 | ``` 34 | 35 | results in: 36 | 37 | ```text 38 | AD 39 | BE 40 | C 41 | ``` 42 | 43 | And transposing: 44 | 45 | ```text 46 | AB 47 | DEF 48 | ``` 49 | 50 | results in: 51 | 52 | ```text 53 | AD 54 | BE 55 | F 56 | ``` 57 | 58 | In general, all characters from the input should also be present in the transposed output. 59 | That means that if a column in the input text contains only spaces on its bottom-most row(s), the corresponding output row should contain the spaces in its right-most column(s). 60 | 61 | [transpose]: https://en.wikipedia.org/wiki/Transpose 62 | -------------------------------------------------------------------------------- /exercises/practice/transpose/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "transpose.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Take input text and output it transposed.", 17 | "source": "Reddit r/dailyprogrammer challenge #270 [Easy].", 18 | "source_url": "https://web.archive.org/web/20230630051421/https://old.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text/" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/transpose/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun transpose (lines: string list): string list = 2 | let 3 | fun spaces (n: int): string = 4 | if n = 0 then "" 5 | else " " ^ spaces (n -1) 6 | 7 | fun generateLine (index: int): string = 8 | let 9 | fun recurse (gap: int) (remaining: string list): string = 10 | case remaining of 11 | nil => "" 12 | | first :: rest => 13 | if index >= size first then recurse (gap + 1) rest 14 | else (spaces gap) ^ (String.substring(first, index, 1)) ^ (recurse 0 rest) 15 | in 16 | recurse 0 lines 17 | end 18 | 19 | fun generateLines (index: int): string list = 20 | let 21 | val line = generateLine index 22 | in 23 | if line = "" then nil 24 | else line :: generateLines (index + 1) 25 | end 26 | in 27 | generateLines 0 28 | end 29 | 30 | -------------------------------------------------------------------------------- /exercises/practice/transpose/transpose.sml: -------------------------------------------------------------------------------- 1 | fun transpose (lines: string list): string list = 2 | raise Fail "'transpose' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/triangle/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Determine if a triangle is equilateral, isosceles, or scalene. 4 | 5 | An _equilateral_ triangle has all three sides the same length. 6 | 7 | An _isosceles_ triangle has at least two sides the same length. 8 | (It is sometimes specified as having exactly two sides the same length, but for the purposes of this exercise we'll say at least two.) 9 | 10 | A _scalene_ triangle has all sides of different lengths. 11 | 12 | ## Note 13 | 14 | For a shape to be a triangle at all, all sides have to be of length > 0, and the sum of the lengths of any two sides must be greater than or equal to the length of the third side. 15 | 16 | In equations: 17 | 18 | Let `a`, `b`, and `c` be sides of the triangle. 19 | Then all three of the following expressions must be true: 20 | 21 | ```text 22 | a + b ≥ c 23 | b + c ≥ a 24 | a + c ≥ b 25 | ``` 26 | 27 | See [Triangle Inequality][triangle-inequality] 28 | 29 | [triangle-inequality]: https://en.wikipedia.org/wiki/Triangle_inequality 30 | -------------------------------------------------------------------------------- /exercises/practice/triangle/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "rainij" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "triangle.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Determine if a triangle is equilateral, isosceles, or scalene.", 17 | "source": "The Ruby Koans triangle project, parts 1 & 2", 18 | "source_url": "https://web.archive.org/web/20220831105330/http://rubykoans.com" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/triangle/.meta/example.sml: -------------------------------------------------------------------------------- 1 | infix == (* For some reason this is only necessary for *some* comparision operators *) 2 | val op== = Real.== 3 | 4 | fun equilateral ([a, b, c]: real list) = (a > 0.0) andalso (a == b) andalso (b == c) 5 | | equilateral _ = false 6 | 7 | 8 | fun isosceles ([a, b, c]: real list) = 9 | let 10 | fun pred (x, y, z) = x == y andalso x + y > z andalso z > 0.0 11 | in 12 | pred (a, b, c) orelse pred (b, c, a) orelse pred (c, a, b) 13 | end 14 | | isosceles _ = false 15 | 16 | 17 | fun scalene ([a, b, c]: real list) = 18 | let 19 | fun pred (x, y, z) = Real.!= (x, y) andalso x + y > z andalso z > 0.0 20 | in 21 | pred (a, b, c) andalso pred (b, c, a) andalso pred (c, a, b) 22 | end 23 | | scalene _ = false 24 | -------------------------------------------------------------------------------- /exercises/practice/triangle/triangle.sml: -------------------------------------------------------------------------------- 1 | fun equilateral (sides: real list): bool = 2 | raise Fail "'equilateral' is not implemented" 3 | 4 | fun isosceles (sides: real list): bool = 5 | raise Fail "'isosceles' is not implemented" 6 | 7 | fun scalene (sides: real list): bool = 8 | raise Fail "'scalene' is not implemented" 9 | -------------------------------------------------------------------------------- /exercises/practice/twelve-days/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "twelve-days.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Output the lyrics to 'The Twelve Days of Christmas'.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/The_Twelve_Days_of_Christmas_(song)" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/twelve-days/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun recite (startVerse: int, endVerse: int): string = 2 | let 3 | val ordinals = [ "", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth" ] 4 | 5 | val ordinal = List.nth (ordinals, startVerse) 6 | 7 | val offsets = [ 0, 235, 213, 194, 174, 157, 137, 113, 90, 69, 48, 26, 0 ] 8 | 9 | val offset = List.nth (offsets, startVerse) 10 | 11 | val gifts = "twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree." 12 | 13 | val gift = String.substring (gifts, offset, String.size gifts - offset) 14 | 15 | val suffix = if startVerse = endVerse then "" else "\n" ^ recite (startVerse + 1, endVerse) 16 | in 17 | "On the " ^ ordinal ^ " day of Christmas my true love gave to me: " ^ gift ^ suffix 18 | end 19 | -------------------------------------------------------------------------------- /exercises/practice/twelve-days/twelve-days.sml: -------------------------------------------------------------------------------- 1 | fun recite (startVerse: int, endVerse: int): string = 2 | raise Fail "'recite' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine what you will say as you give away the extra cookie. 4 | 5 | If you know the person's name (e.g. if they're named Do-yun), then you will say: 6 | 7 | ```text 8 | One for Do-yun, one for me. 9 | ``` 10 | 11 | If you don't know the person's name, you will say _you_ instead. 12 | 13 | ```text 14 | One for you, one for me. 15 | ``` 16 | 17 | Here are some examples: 18 | 19 | | Name | Dialogue | 20 | | :----- | :-------------------------- | 21 | | Alice | One for Alice, one for me. | 22 | | Bohdan | One for Bohdan, one for me. | 23 | | | One for you, one for me. | 24 | | Zaphod | One for Zaphod, one for me. | 25 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | In some English accents, when you say "two for" quickly, it sounds like "two fer". 4 | Two-for-one is a way of saying that if you buy one, you also get one for free. 5 | So the phrase "two-fer" often implies a two-for-one offer. 6 | 7 | Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). 8 | You take the offer and (very generously) decide to give the extra cookie to someone else in the queue. 9 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "snahor" 4 | ], 5 | "contributors": [ 6 | "iHiD", 7 | "mcmillhj-wta", 8 | "sjwarner-bp", 9 | "sshine" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "two-fer.sml" 14 | ], 15 | "test": [ 16 | "test.sml" 17 | ], 18 | "example": [ 19 | ".meta/example.sml" 20 | ] 21 | }, 22 | "blurb": "Create a sentence of the form \"One for X, one for me.\".", 23 | "source_url": "https://github.com/exercism/problem-specifications/issues/757" 24 | } 25 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.meta/example.sml: -------------------------------------------------------------------------------- 1 | fun name input = "One for " ^ getOpt (input, "you") ^ ", one for me." 2 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [1cf3e15a-a3d7-4a87-aeb3-ba1b43bc8dce] 13 | description = "no name given" 14 | 15 | [b4c6dbb8-b4fb-42c2-bafd-10785abe7709] 16 | description = "a name given" 17 | 18 | [3549048d-1a6e-4653-9a79-b0bda163e8d5] 19 | description = "another name given" 20 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/test.sml: -------------------------------------------------------------------------------- 1 | (* version 1.1.0 *) 2 | 3 | use "testlib.sml"; 4 | use "two-fer.sml"; 5 | 6 | infixr |> 7 | fun x |> f = f x 8 | 9 | val testsuite = 10 | describe "two-fer" [ 11 | test "no name given" 12 | (fn _ => name (NONE) |> Expect.equalTo "One for you, one for me."), 13 | 14 | test "a name given" 15 | (fn _ => name (SOME "Alice") |> Expect.equalTo "One for Alice, one for me."), 16 | 17 | test "another name given" 18 | (fn _ => name (SOME "Bob") |> Expect.equalTo "One for Bob, one for me.") 19 | ] 20 | 21 | val _ = Test.run testsuite 22 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/two-fer.sml: -------------------------------------------------------------------------------- 1 | fun name (input: string option) = 2 | raise Fail "'name' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/wordy/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "wordy.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Parse and evaluate simple math word problems returning the answer as an integer.", 17 | "source": "Inspired by one of the generated questions in the Extreme Startup game.", 18 | "source_url": "https://github.com/rchatley/extreme_startup" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/wordy/wordy.sml: -------------------------------------------------------------------------------- 1 | fun answer (question: string): int option = 2 | raise Fail "'answer' is not implemented" 3 | -------------------------------------------------------------------------------- /exercises/practice/yacht/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Each year, something new is "all the rage" in your high school. 4 | This year it is a dice game: [Yacht][yacht]. 5 | 6 | The game of Yacht is from the same family as Poker Dice, Generala and particularly Yahtzee, of which it is a precursor. 7 | The game consists of twelve rounds. 8 | In each, five dice are rolled and the player chooses one of twelve categories. 9 | The chosen category is then used to score the throw of the dice. 10 | 11 | [yacht]: https://en.wikipedia.org/wiki/Yacht_(dice_game) 12 | -------------------------------------------------------------------------------- /exercises/practice/yacht/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "keiravillekode" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "yacht.sml" 8 | ], 9 | "test": [ 10 | "test.sml" 11 | ], 12 | "example": [ 13 | ".meta/example.sml" 14 | ] 15 | }, 16 | "blurb": "Score a single throw of dice in the game Yacht.", 17 | "source": "James Kilfiger, using Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Yacht_(dice_game)" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/yacht/yacht.sml: -------------------------------------------------------------------------------- 1 | datatype category = 2 | Ones 3 | | Twos 4 | | Threes 5 | | Fours 6 | | Fives 7 | | Sixes 8 | | FullHouse 9 | | FourOfAKind 10 | | LittleStraight 11 | | BigStraight 12 | | Choice 13 | | Yacht 14 | 15 | fun score (dice: int list, category): int = 16 | raise Fail "'score' is not implemented" 17 | -------------------------------------------------------------------------------- /exercises/shared/.docs/help.md: -------------------------------------------------------------------------------- 1 | # Help 2 | 3 | To get help if you're having trouble, you can use one of the following resources: 4 | 5 | - [The Definition of Standard ML](https://github.com/SMLFamily/The-Definition-of-Standard-ML-Revised) 6 | - [/r/sml](https://www.reddit.com/r/sml) is the Standard ML subreddit. 7 | - [StackOverflow](http://stackoverflow.com/questions/tagged/sml) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. 8 | -------------------------------------------------------------------------------- /exercises/shared/.docs/tests.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | You can run the tests by opening a command prompt in the exercise's directory, and then running: 4 | 5 | ```bash 6 | $ poly -q --use test.sml 7 | ``` 8 | --------------------------------------------------------------------------------