There's a lot of conflicting information online about using Haskell, Nix, Stack, Cabal, and Spacemacs together. Here's what has worked and not worked for me.
default.nix
:
{ pkgs ? import <nixpkgs> {} }:
pkgs.haskellPackages.callCabal2nix "name" ./. { }
shell.nix
:
with import <nixpkgs> { };
let name = import ./default.nix { };
in stdenv.mkDerivation {
name = "name-dev";
version = "0.1";
src = lib.sourceFilesBySuffices ./. [ ".cabal" ".hs" ];
buildInputs = [
# You can specify a GHC version like so:
# haskell.packages.ghc843.ghcWithPackages
(haskellPackages.ghcWithPackages (hpkgs: with hpkgs; [
cabal-install
hoogle
hlint
hindent
ghcid
packunused
# ghc-mod # Broken on GHC 843
# hasktags # Broken on GHC 843
] ++ name.buildInputs ++ name.propagatedBuildInputs))
# General development
emacs
git
sourceHighlight # Use with ghcid
haskellPackages.unused # https://unused.codes/
zsh
];
}
If you get an error like this (especially after modifying your nix or cabal files), it's time to re-run cabal configure
:
<command line>: cannot satisfy -package-id brick-0.38-9Yht4H8pMMu8WmuSHutUhb
(use -v for more information)
Unfortunately, it is a known bug that Spacemacs destroys your PATH
from nix-shell
. This means that all of this is basically unusable, except through an ansi-term
in which you also execute nix-shell --pure
.
However, using emacs-direnv will fix the PATH
if the following is put in .envrc
:
use_nix shell.nix
For some reason, I had to configure dante to use nix-shell --pure
in my dotspacemacs/user-config
:
(setq dante-repl-command-line '("nix-shell" "--pure" "--run" "cabal repl --builddir=dist/dante"))
Sometimes, Dante will have trouble because cabal repl
"doesn't support multiple targets", in which case this works in .dir-locals.el
:
((haskell-mode
. ((dante-repl-command-line . ("nix-shell" "--pure" "--run" "cabal repl lib:saw-script --builddir=dist/dante")))))
This is a small guide to a two-monitor workflow for writing Haskell that is akin to agda-mode
.
- Run
SPC SPC flycheck-list-errors
- Close the pop-up window without closing the buffer:
SPC w d
- Open a new frame with
SPC F n
- Put your new frame on your second monitor, and open the Flycheck buffer
- Leave holes
_
in your expressions
Now when you leave a hole, Flycheck will get it's type from GHC automatically and show it to you in your second window!
Thank you so much!