Adding to a Project

Adding Shpadoinkle to a project should be easy.

See an example of this working by examining default.nix in the Seed Project. You can add packages from Hackage and standard Haskell toolchain.

GHCjs Challenges

Introducing GHCjs brings a host of problems that are solved with Nix. For example, many Haskell packages use a library called doctest. This is not compatible with GHCjs and will prevent dependencies from building.

Likewise, there are other impedances introduced by testing libraries and other minor odds and ends that make packages that should work just fine with GHCjs fail to build.

Additionally, the stock GHCjs and the GHCjs package set is not optimized. It lacks some critical optimizations that have their source of truth in Reflex Platform. These optimizations require custom compilation of the GHCjs compiler as well as many downstream packages this project depends on.

This is addressed as they come by building up Nix package overlays.

Overlays provide a method to extend and change nixpkgs. They replace constructs like packageOverride and overridePackages.

By exposing overlays we allow you to compose needed changes into the nixpkgs set for your existing project.

shpadoinkle = builtins.fetchGit { (1)
  url    = https://gitlab.com/fresheyeball/Shpadoinkle.git;
  rev    = "f4a90d2621aeb981bc0b5b1aaf6d86e19f6d0166";
};

shpadoinkle-overlay = (2)
  import (shpadoinkle + "/nix/overlay.nix") { compiler = "ghc863"; isJS = false; };

pkgs = import
  (builtins.fetchTarball { url = "https://github.com/${fork}/nixpkgs/archive/${rev}.tar.gz"; })
  { overlays = [ shpadoinkle-overlay my-overlay ]; }; (3)
1 Get the Shpadoinkle source code.
2 This overlay makes dependencies compatible with Shpadoinkle targets as well as adds in optimizations of GHCjs from Reflex Platform.
3 Compose the overlays onto your package set.

Extending Nix Haskell

Extending the Haskell package sets in Nix has some pitfalls, as follows:

No Implicit GHC Version

These overlays target a specific compiler version, and so are applied to targets such as pkgs.haskell.packages.ghc863 and not applied to targets like pkgs.haskellPackages. If you modify haskellPackages in your overlay, it will be orthogonal to the ones provided.

You might expect that if the compiler version targeted is the same as the implicit version in haskellPackages, modifications would be kept in sync; this is not the case.

Compose Extensions

If overlays modifying Haskell package sets do not use composeExtensions, new overlays will simply replace previous ones instead of composing together. Follow this pattern and everything will be OK:

self: super:
let
  shpadoinkle = fetchgit { (1)
    url    = https://gitlab.com/fresheyeball/Shpadoinkle.git;
    rev    = "243b89a00c29cdce6768be1b743e846a0bc22fea";
    sha256 = "06v4mgni4nq7asxy96761hgrdzhlva36vzak0l4yxc727zfwrffr";
  };
  haskell-overlay = hself: hsuper: { (2)
    Shpadoinkle      = hself.callCabal2nix "Shpadoinkle"      (shpadoinkle + "/core");
    Shpadoinkle-html = hself.callCabal2nix "Shpadoinkle-html" (shpadoinkle + "/html");
  };
in {
haskell = super.haskell //
  { packages = super.haskell.packages //
    { ghc863 = super.haskell.packages.ghc863.override (old: { (3)
        overrides = super.lib.composeExtensions (4)
          (old.overrides or (_: _: {})) haskell-overlay;
      });
    };
  };
}
1 Here for illustrative reasons
2 Add packages in your application’s Haskell overlay.
3 Override a specific compiler version, not haskellPackages.
4 Use composeExtensions to preserve work done in earlier overlays