first two easy exercises
This commit is contained in:
commit
8c221fed78
20 changed files with 562 additions and 0 deletions
4
.envrc
Normal file
4
.envrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
# shellcheck shell=bash
|
||||
# For use with direnv.
|
||||
# Installing nix-direnv will ensure a smoother experience.
|
||||
use flake
|
23
dune-project
Normal file
23
dune-project
Normal file
|
@ -0,0 +1,23 @@
|
|||
(lang dune 3.2)
|
||||
|
||||
(name exercism)
|
||||
|
||||
(generate_opam_files false)
|
||||
|
||||
(source
|
||||
(uri https://gitea.vp.mk/vladan/exercism))
|
||||
|
||||
(authors "Vladan Popovic")
|
||||
(maintainers "Vladan Popovic")
|
||||
|
||||
(license LICENSE)
|
||||
|
||||
(package
|
||||
(name exercism)
|
||||
(synopsis "Exercism OCaml exercises")
|
||||
(description "Exercism OCaml exercises")
|
||||
(depends ocaml dune)
|
||||
(tags
|
||||
(exercism "Exercism OCaml exercises")))
|
||||
|
||||
; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project
|
57
flake.lock
generated
Normal file
57
flake.lock
generated
Normal file
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-filter": {
|
||||
"locked": {
|
||||
"lastModified": 1666547822,
|
||||
"narHash": "sha256-razwnAybPHyoAyhkKCwXdxihIqJi1G6e1XP4FQOJTEs=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-filter",
|
||||
"rev": "1a3b735e13e90a8d2fd5629f2f8363bd7ffbbec7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-filter",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1669867399,
|
||||
"narHash": "sha256-Z8RXSFYOsIsTG96ROKtV0eZ8Q7u4irFWm6ELqfw7mT8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "38e591dd05ffc8bdf79dc752ba78b05e370416fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-filter": "nix-filter",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
214
flake.nix
Normal file
214
flake.nix
Normal file
|
@ -0,0 +1,214 @@
|
|||
{
|
||||
description = "A flake demonstrating how to build OCaml projects with Dune";
|
||||
|
||||
# Flake dependency specification
|
||||
#
|
||||
# To update all flake inputs:
|
||||
#
|
||||
# $ nix flake update --commit-lockfile
|
||||
#
|
||||
# To update individual flake inputs:
|
||||
#
|
||||
# $ nix flake lock --update-input <input> ... --commit-lockfile
|
||||
#
|
||||
inputs = {
|
||||
# Convenience functions for writing flakes
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
# Precisely filter files copied to the nix store
|
||||
nix-filter.url = "github:numtide/nix-filter";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, nix-filter }:
|
||||
# Construct an output set that supports a number of default systems
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
# Legacy packages that have not been converted to flakes
|
||||
legacyPackages = nixpkgs.legacyPackages.${system};
|
||||
# OCaml packages available on nixpkgs
|
||||
ocamlPackages = legacyPackages.ocamlPackages;
|
||||
# Library functions from nixpkgs
|
||||
lib = legacyPackages.lib;
|
||||
|
||||
# Filtered sources (prevents unecessary rebuilds)
|
||||
sources = {
|
||||
ocaml = nix-filter.lib {
|
||||
root = ./.;
|
||||
include = [
|
||||
".ocamlformat"
|
||||
"dune-project"
|
||||
(nix-filter.lib.inDirectory "bin")
|
||||
(nix-filter.lib.inDirectory "lib")
|
||||
(nix-filter.lib.inDirectory "test")
|
||||
];
|
||||
};
|
||||
|
||||
nix = nix-filter.lib {
|
||||
root = ./.;
|
||||
include = [
|
||||
(nix-filter.lib.matchExt "nix")
|
||||
];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
# Exposed packages that can be built or run with `nix build` or
|
||||
# `nix run` respectively:
|
||||
#
|
||||
# $ nix build .#<name>
|
||||
# $ nix run .#<name> -- <args?>
|
||||
#
|
||||
packages = {
|
||||
# The package that will be built or run by default. For example:
|
||||
#
|
||||
# $ nix build
|
||||
# $ nix run -- <args?>
|
||||
#
|
||||
default = self.packages.${system}.exercism;
|
||||
|
||||
exercism = ocamlPackages.buildDunePackage {
|
||||
pname = "exercism";
|
||||
version = "0.1.0";
|
||||
duneVersion = "3";
|
||||
src = sources.ocaml;
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
preBuild = ''
|
||||
dune build exercism.opam
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# Flake checks
|
||||
#
|
||||
# $ nix flake check
|
||||
#
|
||||
checks = {
|
||||
# Run tests for the `exercism` package
|
||||
exercism =
|
||||
let
|
||||
# Patches calls to dune commands to produce log-friendly output
|
||||
# when using `nix ... --print-build-log`. Ideally there would be
|
||||
# support for one or more of the following:
|
||||
#
|
||||
# In Dune:
|
||||
#
|
||||
# - have workspace-specific dune configuration files
|
||||
#
|
||||
# In NixPkgs:
|
||||
#
|
||||
# - allow dune flags to be set in in `ocamlPackages.buildDunePackage`
|
||||
# - alter `ocamlPackages.buildDunePackage` to use `--display=short`
|
||||
# - alter `ocamlPackages.buildDunePackage` to allow `--config-file=FILE` to be set
|
||||
patchDuneCommand =
|
||||
let
|
||||
subcmds = [ "build" "test" "runtest" "install" ];
|
||||
in
|
||||
lib.replaceStrings
|
||||
(lib.lists.map (subcmd: "dune ${subcmd}") subcmds)
|
||||
(lib.lists.map (subcmd: "dune ${subcmd} --display=short") subcmds);
|
||||
in
|
||||
|
||||
self.packages.${system}.exercism.overrideAttrs
|
||||
(oldAttrs: {
|
||||
name = "check-${oldAttrs.name}";
|
||||
doCheck = true;
|
||||
buildPhase = patchDuneCommand oldAttrs.buildPhase;
|
||||
checkPhase = patchDuneCommand oldAttrs.checkPhase;
|
||||
# skip installation (this will be tested in the `exercism-app` check)
|
||||
installPhase = "touch $out";
|
||||
});
|
||||
|
||||
# Check Dune and OCaml formatting
|
||||
dune-fmt = legacyPackages.runCommand "check-dune-fmt"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
ocamlPackages.dune_3
|
||||
ocamlPackages.ocaml
|
||||
legacyPackages.ocamlformat
|
||||
];
|
||||
}
|
||||
''
|
||||
echo "checking dune and ocaml formatting"
|
||||
dune build \
|
||||
--display=short \
|
||||
--no-print-directory \
|
||||
--root="${sources.ocaml}" \
|
||||
--build-dir="$(pwd)/_build" \
|
||||
@fmt
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# Check documentation generation
|
||||
dune-doc = legacyPackages.runCommand "check-dune-doc"
|
||||
{
|
||||
ODOC_WARN_ERROR = "true";
|
||||
nativeBuildInputs = [
|
||||
ocamlPackages.dune_3
|
||||
ocamlPackages.ocaml
|
||||
ocamlPackages.odoc
|
||||
];
|
||||
}
|
||||
''
|
||||
echo "checking ocaml documentation"
|
||||
dune build \
|
||||
--display=short \
|
||||
--no-print-directory \
|
||||
--root="${sources.ocaml}" \
|
||||
--build-dir="$(pwd)/_build" \
|
||||
@doc
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# Check Nix formatting
|
||||
nixpkgs-fmt = legacyPackages.runCommand "check-nixpkgs-fmt"
|
||||
{ nativeBuildInputs = [ legacyPackages.nixpkgs-fmt ]; }
|
||||
''
|
||||
echo "checking nix formatting"
|
||||
nixpkgs-fmt --check ${sources.nix}
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
|
||||
# Development shells
|
||||
#
|
||||
# $ nix develop .#<name>
|
||||
# $ nix develop .#<name> --command dune build @test
|
||||
#
|
||||
# [Direnv](https://direnv.net/) is recommended for automatically loading
|
||||
# development environments in your shell. For example:
|
||||
#
|
||||
# $ echo "use flake" > .envrc && direnv allow
|
||||
# $ dune build @test
|
||||
#
|
||||
devShells = {
|
||||
default = legacyPackages.mkShell {
|
||||
# Development tools
|
||||
packages = [
|
||||
# Source file formatting
|
||||
legacyPackages.nixpkgs-fmt
|
||||
legacyPackages.ocamlformat
|
||||
# For `dune build --watch ...`
|
||||
legacyPackages.fswatch
|
||||
# For `dune build @doc`
|
||||
ocamlPackages.odoc
|
||||
# OCaml editor support
|
||||
ocamlPackages.ocaml-lsp
|
||||
# Nicely formatted types on hover
|
||||
ocamlPackages.ocamlformat-rpc-lib
|
||||
# Fancy REPL thing
|
||||
ocamlPackages.utop
|
||||
ocamlPackages.angstrom
|
||||
ocamlPackages.ounit
|
||||
ocamlPackages.ounit2
|
||||
ocamlPackages.ppx_sexp_conv
|
||||
];
|
||||
|
||||
# Tools from packages
|
||||
inputsFrom = [
|
||||
self.packages.${system}.exercism
|
||||
];
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
36
hello-world/HELP.md
Normal file
36
hello-world/HELP.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
A `Makefile` is provided with a default target to compile your solution and run the tests. At the command line in your exercise's directory, type:
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit hello_world.ml` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [OCaml track's documentation](https://exercism.org/docs/tracks/ocaml)
|
||||
- The [OCaml track's programming category on the forum](https://forum.exercism.org/c/programming/ocaml)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [Documentation for the Standard Library](http://caml.inria.fr/pub/docs/manual-ocaml/libref/index.html)
|
||||
- [/r/ocaml](https://www.reddit.com/r/ocaml) is the OCaml subreddit.
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/ocaml) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
9
hello-world/Makefile
Normal file
9
hello-world/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
default: clean test
|
||||
|
||||
test:
|
||||
dune runtest
|
||||
|
||||
clean:
|
||||
dune clean
|
||||
|
||||
.PHONY: clean
|
42
hello-world/README.md
Normal file
42
hello-world/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Hello World
|
||||
|
||||
Welcome to Hello World on Exercism's OCaml Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
The classical introductory exercise.
|
||||
Just say "Hello, World!".
|
||||
|
||||
["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment.
|
||||
|
||||
The objectives are simple:
|
||||
|
||||
- Modify the provided code so that it produces the string "Hello, World!".
|
||||
- Run the test suite and make sure that it succeeds.
|
||||
- Submit your solution and check it at the website.
|
||||
|
||||
If everything goes well, you will be ready to fetch your first real exercise.
|
||||
|
||||
[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @dvberkel
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @daveyarwood
|
||||
- @iHiD
|
||||
- @kytrinyx
|
||||
- @marionebl
|
||||
- @Peaupote
|
||||
- @sbl
|
||||
- @sshine
|
||||
- @stevejb71
|
||||
|
||||
### Based on
|
||||
|
||||
This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
16
hello-world/dune
Normal file
16
hello-world/dune
Normal file
|
@ -0,0 +1,16 @@
|
|||
(executable
|
||||
(name test)
|
||||
(libraries base ounit2))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (:x test.exe))
|
||||
(action (run %{x})))
|
||||
|
||||
(alias
|
||||
(name buildtest)
|
||||
(deps (:x test.exe)))
|
||||
|
||||
(env
|
||||
(dev
|
||||
(flags (:standard -warn-error -A))))
|
1
hello-world/dune-project
Normal file
1
hello-world/dune-project
Normal file
|
@ -0,0 +1 @@
|
|||
(lang dune 1.1)
|
1
hello-world/hello_world.ml
Normal file
1
hello-world/hello_world.ml
Normal file
|
@ -0,0 +1 @@
|
|||
let hello = "Hello, World!"
|
4
hello-world/hello_world.mli
Normal file
4
hello-world/hello_world.mli
Normal file
|
@ -0,0 +1,4 @@
|
|||
(*
|
||||
Returns "Hello, World!"
|
||||
*)
|
||||
val hello: string
|
11
hello-world/test.ml
Normal file
11
hello-world/test.ml
Normal file
|
@ -0,0 +1,11 @@
|
|||
open OUnit2
|
||||
open Hello_world
|
||||
|
||||
let ae exp got _test_ctxt = assert_equal ~printer:(fun x -> x) exp got
|
||||
|
||||
let tests = [
|
||||
"Say Hi!" >:: ae "Hello, World!" hello;
|
||||
]
|
||||
|
||||
let () =
|
||||
run_test_tt_main ("Hello World tests" >::: tests)
|
36
leap/HELP.md
Normal file
36
leap/HELP.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
A `Makefile` is provided with a default target to compile your solution and run the tests. At the command line in your exercise's directory, type:
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit leap.ml` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [OCaml track's documentation](https://exercism.org/docs/tracks/ocaml)
|
||||
- The [OCaml track's programming category on the forum](https://forum.exercism.org/c/programming/ocaml)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [Documentation for the Standard Library](http://caml.inria.fr/pub/docs/manual-ocaml/libref/index.html)
|
||||
- [/r/ocaml](https://www.reddit.com/r/ocaml) is the OCaml subreddit.
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/ocaml) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
9
leap/Makefile
Normal file
9
leap/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
default: clean test
|
||||
|
||||
test:
|
||||
dune runtest
|
||||
|
||||
clean:
|
||||
dune clean
|
||||
|
||||
.PHONY: clean
|
51
leap/README.md
Normal file
51
leap/README.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Leap
|
||||
|
||||
Welcome to Leap on Exercism's OCaml Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Given a year, report if it is a leap year.
|
||||
|
||||
The tricky thing here is that a leap year in the Gregorian calendar occurs:
|
||||
|
||||
```text
|
||||
on every year that is evenly divisible by 4
|
||||
except every year that is evenly divisible by 100
|
||||
unless the year is also evenly divisible by 400
|
||||
```
|
||||
|
||||
For example, 1997 is not a leap year, but 1996 is.
|
||||
1900 is not a leap year, but 2000 is.
|
||||
|
||||
## Notes
|
||||
|
||||
Though our exercise adopts some very simple rules, there is more to learn!
|
||||
|
||||
For a delightful, four minute explanation of the whole leap year phenomenon, go watch [this youtube video][video].
|
||||
|
||||
[video]: https://www.youtube.com/watch?v=xX96xng7sAE
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @tmcgilchrist
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @daveyarwood
|
||||
- @dvberkel
|
||||
- @iHiD
|
||||
- @ismaelga
|
||||
- @kytrinyx
|
||||
- @marionebl
|
||||
- @Peaupote
|
||||
- @pminten
|
||||
- @sbl
|
||||
- @sshine
|
||||
- @stevejb71
|
||||
|
||||
### Based on
|
||||
|
||||
CodeRanch Cattle Drive, Assignment 3 - https://coderanch.com/t/718816/Leap
|
16
leap/dune
Normal file
16
leap/dune
Normal file
|
@ -0,0 +1,16 @@
|
|||
(executable
|
||||
(name test)
|
||||
(libraries base ounit2))
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (:x test.exe))
|
||||
(action (run %{x})))
|
||||
|
||||
(alias
|
||||
(name buildtest)
|
||||
(deps (:x test.exe)))
|
||||
|
||||
(env
|
||||
(dev
|
||||
(flags (:standard -warn-error -A))))
|
1
leap/dune-project
Normal file
1
leap/dune-project
Normal file
|
@ -0,0 +1 @@
|
|||
(lang dune 1.1)
|
2
leap/leap.ml
Normal file
2
leap/leap.ml
Normal file
|
@ -0,0 +1,2 @@
|
|||
let leap_year year =
|
||||
(year mod 4 = 0 && year mod 100 <> 0) || year mod 400 = 0
|
1
leap/leap.mli
Normal file
1
leap/leap.mli
Normal file
|
@ -0,0 +1 @@
|
|||
val leap_year: int -> bool
|
28
leap/test.ml
Normal file
28
leap/test.ml
Normal file
|
@ -0,0 +1,28 @@
|
|||
open OUnit2
|
||||
open Leap
|
||||
|
||||
let ae exp got _test_ctxt = assert_equal exp got ~printer:string_of_bool
|
||||
|
||||
let tests = [
|
||||
"year not divisible by 4 in common year" >::
|
||||
ae false (leap_year 2015);
|
||||
"year divisible by 2, not divisible by 4 in common year" >::
|
||||
ae false (leap_year 1970);
|
||||
"year divisible by 4, not divisible by 100 in leap year" >::
|
||||
ae true (leap_year 1996);
|
||||
"year divisible by 4 and 5 is still a leap year" >::
|
||||
ae true (leap_year 1960);
|
||||
"year divisible by 100, not divisible by 400 in common year" >::
|
||||
ae false (leap_year 2100);
|
||||
"year divisible by 100 but not by 3 is still not a leap year" >::
|
||||
ae false (leap_year 1900);
|
||||
"year divisible by 400 is leap year" >::
|
||||
ae true (leap_year 2000);
|
||||
"year divisible by 400 but not by 125 is still a leap year" >::
|
||||
ae true (leap_year 2400);
|
||||
"year divisible by 200, not divisible by 400 in common year" >::
|
||||
ae false (leap_year 1800);
|
||||
]
|
||||
|
||||
let () =
|
||||
run_test_tt_main ("leap tests" >::: tests)
|
Loading…
Add table
Reference in a new issue