How to achieve anything like "cabal typecheck"

In Rust, there is the immensely useful “cargo check” command, which typechecks the whole codebase. It just works. I expect any command like that to be even more useful in Haskell, since we use a lot of type level stuff in Haskell!

But I can’t seem to make it work for cabal in any nontrivial way. Sometimes you see a recommendation of cabal build --ghc-options="-fno-code", and this may work for small, simple, single cabal packages. But it doesn’t work, it seems, already for cabal projects with more than one package. I doubt it would work for template haskell.

This seems like a huge omission in Haskell’s tooling landscape. Has anyone managed to fill in this gap, maybe with a hack? Or is there any work in progress towards something like this? I couldn’t find anything so far.

1 Like

You could use something like ghcid which will automatically check the project on change.

Personally I prefer to use the language server for this kind of feedback loop.

2 Likes

Can you easily include either ghcid or HLS into a script? For example, I’d really like to do something like git rebase --exec "cabal typecheck to make sure every commit typechecks. I don’t know of a way to do this with ghcid or HLS.

I hadn’t noticed this until now, but you’re right that --ghc-options=-fno-code appears not to work with cabal build (/usr/bin/ar: dist-newstyle/build/x86_64-linux/ghc-9.10.1/hello-hs-0.1.0.0/build/Lib.o: No such file or directory). But it does work with cabal repl, and indeed this is utilised by ghcid. So, unless you’re interested in improving things upstream, you could hack something together by piping commands in to that.

Right, this is the best I’ve got (--enable-multi-repl and all are optional, but useful for multi-component projects):

echo ':set prompt-function \modules _ -> if all (== "Prelude") modules then System.Exit.exitFailure else System.Exit.exitSuccess' | cabal --enable-multi-repl repl all --ghc-options=-fno-code

The options from Interface Files with Core Definitions - Well-Typed: The Haskell Consultants might also be helpful for speeding this up with TH

That prompt-function will exitSuccess when some modules have failed to load, so long as at least one loaded.

Another approach:

#! /usr/bin/env sh

check=$(
	echo ':q' | \
	cabal -O0 repl \
		--enable-multi-repl \
		--repl-options="-ignore-dot-ghci -fdiagnostics-as-json -fno-code" \
		2>&1 | \
	grep '"severity":"Error"'
)

if [ -n "$check" ]; then
	exit 1
fi

Ah, damn. I only tested it with a very simple project.

That sounds really promising, thank you very much! Unfortunately I’m stuck with GHC 8.6 and I can’t do --enable-multi-repl there it seems.