Compositional Representable Executable Machines
Go to file
2023-01-26 14:36:24 +01:00
.github/workflows add CI workflow 2023-01-12 15:37:44 +01:00
.vscode initial setup 2023-01-04 17:33:08 +01:00
decision-log Machines without trivial transitions are not considered 2023-01-26 12:11:29 +01:00
doctest run doctests as part of cabal test 2023-01-13 16:19:04 +01:00
nix run doctests as part of cabal test 2023-01-13 16:19:04 +01:00
spec always allow the identity transition 2023-01-26 12:11:29 +01:00
src/CRM state machines have an instance of Choice 2023-01-26 14:36:24 +01:00
.envrc initial setup 2023-01-04 17:33:08 +01:00
.gitattributes initial setup 2023-01-04 17:33:08 +01:00
.gitignore run doctests as part of cabal test 2023-01-13 16:19:04 +01:00
.hspec run doctests as part of cabal test 2023-01-13 16:19:04 +01:00
flake.lock refactor a bit of nix so that we can use wingman on ghc 9.0 2023-01-11 12:07:57 +01:00
flake.nix remove --color option from tests 2023-01-16 17:39:09 +01:00
fourmolu.yaml use single-line Haddock comments 2023-01-13 16:19:04 +01:00
hie.yaml initial setup 2023-01-04 17:33:08 +01:00
package.yaml run doctests as part of cabal test 2023-01-13 16:19:04 +01:00
README.md rename to crem 2023-01-16 17:06:09 +01:00
shell.nix initial setup 2023-01-04 17:33:08 +01:00

crem

crem stands for compositional representable executable machines

development

This is a Haskell Cabal project that uses Nix for development. Nix is optional but recommended.

environment

A Nix shell is available with all the required tools. To enter the shell, issue

# default GHC
nix develop

# custom GHC
nix develop .#ghc90
nix develop .#ghc92

Or, without flakes:

# default GHC
nix-shell

GHC version

The project has a default GHC version that is specified in the flake. At the moment that version is 9.0, because the HLS plugin Wingman currently only builds up to this version.

It is also possible to use other GHC versions to build the project and enter development shells. This allows us to easily test multiple versions.

Building

In a development shell, you can simply build the project with Cabal:

cabal build

This provides us fast incremental builds, ease of debugging, etc.

It is also possible to build the project without entering the development shell. This allows us to build the same way as the CI/CD environment, build with different GHC versions, build container images, etc.

To do this, run

# default GHC
nix build

# custom GHC
nix build .#crm.ghc90
nix build .#crm.ghc92

To view the compilation logs, you can append -L:

nix build -L
nix build -L .#crm.ghc92

project setup

  • flake.nix

This file specifies our project's dependencies and outputs/artefacts. Some common dependencies for a Haskell project are the GHC and Cabal, but during development we also use HLS, hpack, .... Nix flake dependencies are called inputs, and are usually Git repositories (e.g. from GitHub, GitLab, ...), but they can be any web-accessible resource.

By using Nix and Nixpkgs, the developers do not have to have those tools installed on their machines, manage their versions, etc. It also allows us to create other controlled environments, such as container images for CI/CD.

The project should still build without Nix, because Nix does not change any project files. This means you must have Cabal and system libraries installed manually.

  • flake.lock

This file is automatically generated and updated by Nix, when evaluating the flake.nix file. It contains the timestamps and hashes of each input at the time of last update.

An input coupled with a timestamp and hash of its contents is called a pinned input. Pinning inputs allows us to gurantee reproducibility.

We can specify unpinned inputs in flake.nix; for example, our nixpkgs input is not pinned to a specific commit. The branch nixpkgs-unstable changes almost every day. However, the flake.lock file contains a timestamp and hash of a specific commit in the nixpkgs repository. This is regenerated for every input every time we run nix flake upadate, to the latest commit in the branch/tag we specified in the flake.

We can also update just a single input (e.g. just nixpkgs) and leave the others pinned. One way of doing this is with the command:

nix build . --update-input nixpkgs
  • shell.nix

Nix flakes are a new feature. Some Nix installations do not support them. However, it is still useful to provide a development shell for developers with older Nix versions.

This file allows us to replicate the development shell provided in flake.nix without duplicating the code. This way changes to the flake.nix are automaticaly propagated to the shell.nix.

Some tools also don't yet support flakes. An important example is Visual Studio Code with the Nix Environment Selector plugin: it works with shell.nix, but not flake.nix.

  • hie.yaml

This file instructs the Haskell Language Server how your project should be built. Find more information at https://haskell-language-server.readthedocs.io/en/latest/configuration.html.

  • package.yaml

This file contains the Cabal package specification in Yaml format read by Hpack. It is more abstract and easier to maintain than the Cabal file format.

To generate a .cabal file from a package.yaml file, run the following command:

hpack

Note that Cabal does not understand package.yaml files, and requires us to generate a .cabal file before running cabal. Nix (or more precisely, Cabal2nix) uses a .cabal file if it is present, otherwise the package.yaml file. Because package.yaml is our single source of truth, we would prefer that Nix uses it instead of the generated .cabal. This is why we don't commit the .cabal file.

  • crm.cabal

This file is automatically generated from the package.yaml file and should not be committed to Git history.

tool-specific files

  • fourmolu.yaml

Configuration file for the fourmolu formatting tool.

  • .hspec

Using a dedicated file to specify options for hspec allows passing options only to it. Using cabal test --test-options would pass options to all test stanzas instead.