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!