Liquidhaskell
Liquid Types For Haskell
Install / Use
/learn @ucsd-progsys/LiquidhaskellREADME

This is the development site of the LiquidHaskell formal verification tool.
If you're a LiquidHaskell user (or just curious), you probably want to go to the documentation website instead.
Trying it from Hackage
Assuming the Z3 SMT solver version 4.8.17 or
newer is installed and available in your PATH, you can run
cabal install --lib liquidhaskell liquid-prelude liquid-vector --package-env . --force-reinstalls
ghc -fplugin=LiquidHaskell FILE.hs
--package-env . creates a .ghc.environment* file in the current folder that makes
ghc find the LiquidHaskell plugin only when invoking it from there.
Otherwise, global user configuration would be affected.
Note that the installation step is influenced by the dependencies that are already installed in your system, so different results may be obtained by different users.
Trying it from GitHub
The github repo builds with GHC 9.14.1, cabal-install 3.16.1.0, and z3 9.8.17 or newer, all of
which must be in your PATH.
git clone https://github.com/ucsd-progsys/liquidhaskell.git
cd liquidhaskell
git submodule update --init
cabal build liquidhaskell liquid-prelude liquid-vector
cabal exec -- ghc -fplugin=LiquidHaskell FILE.hs
Asking for Help
If you have questions or you just need help, you can always reach out on our slack channel, google groups mailing list, GitHub issue tracker, or by emailing Ranjit Jhala, Niki Vazou.
Contributing
This is an open-source project, and we love getting feedback (and patches)!
Reporting a Bug
If something doesn't work as it should, please consider opening a github issue to let us know. If possible, try to:
- Try to use a descriptive title;
- State as clearly as possible what is the problem you are facing;
- Provide a small Haskell file producing the issue;
- Write down the expected behaviour vs the actual behaviour;
- Please, let us know which liquidhaskell version you are using.
Your first Pull Request
We are thrilled to get PRs! Please follow these guidelines, as doing so will increase the chances of having your PR accepted:
- The main LH repo lives here
- Please create pull requests against the
developbranch. - Please be sure to include test cases that illustrate the effect of the PR
- e.g. show new features that that are supported or how it fixes some previous issue
- If you're making user-visible changes, please also add documentation
- e.g. options.md, specifications.md, the main tutorial (as relevant)
Pull requests don't just have to be about code: documentation can often be improved too!
General Development Guide
For those diving into the implementation of LiquidHaskell, here are a few tips:
Faster recompilation
When changing the liquidhaskell-boot library, sometimes we don't want
to rebuild liquidhaskell or liquid-vector when testing the changes.
In these cases we can set the environment variable LIQUID_DEV_MODE=true
when running cabal to skip rebuilding those packages.
DANGER: Note that this can give an invalid result if the changes to
liquidhaskell-boot do require rebuilding other liquid* packages.
How To Run Regression Tests
For documentation on the test-driver executable itself, please refer to the
README.md in tests/ or run cabal run tests:test-driver -- --help
You can run all the tests by
$ ./scripts/test/test_plugin.sh
You can run a bunch of particular test-groups instead by
$ ./scripts/test/test_plugin.sh <test-group-name1> <test-group-name2> ...
and you can list all the possible test options with
$ ./scripts/test/test_plugin.sh --help
or get a list of just the test groups, one per line, with
$ ./scripts/test/test_plugin.sh --show-all
To pass in specific parameters, you can invoke cabal directly with
$ cabal build tests:<test-group-name> --ghc-options=-fplugin-opt=LiquidHaskell:--no-termination
For example:
$ cabal build tests:unit-neg --ghc-options=-fplugin-opt=LiquidHaskell:--no-termination
Another useful option is to change the underlying solver:
$ cabal build tests:unit-pos --ghc-options=-fplugin-opt=LiquidHaskell:--smtsolver=cvc5
You can also modify the number of used threads, depending on cores etc.
You can directly extend and run the tests by modifying the files in
tests/harness/
Parallelism in Tests
Tests run in parallel, unless the flag --measure-timings is specified to test_plugin.sh.
How to create performance comparison charts
Firstly, make sure to remove previous compilation artifacts of tests before measuring performance,
or GHC will skip running Liquid Haskell on modules that don't need recompilation. Unfortunately,
using -fforce-recomp is not ideal (see #2565
for more details). At the time of writing, previous compilation artifacts of tests can be removed with
find dist-newstyle -name "tests-*" -o -name "prover-ple-lib-*" | xargs rm -r
When liquidhaskell tests run, we can collect timing information with
$ ./scripts/test/test_plugin.sh --measure-timings
Measures will be collected in .dump-timings files under dist-newstyle directory. These can be
converted to json data with
cabal build ghc-timings
cabal exec ghc-timings dist-newstyle
which will produce tmp/*.json files.
Then a csv report can be generated from the json files with
cabal run benchmark-timings -- tmp/*.json --phase LiquidHaskellCPU -o summary.csv
On each line, the report will contain the CPU time taken by each test.
Use --phase LiquidHaskell to get the wall-clock time instead. Although in that
case you need to use the --measure-timings-j1 option when running the tests,
which validates modules one at a time.
Comparison charts in svg format can be generated by invoking
cabal run plot-performance -- -b path_to_before_summary.csv -a path_to_after_summary.csv -s 50
This will generate two files top.svg and bot.svg containing the top 50 speedups and slowdowns
over the entire test set, both enabled by the -s option) in the current directory. Alternatively,
a subset of the tests can be selected by a prefix of their names with -f <prefix>, for instance
-f benchmarks. -f will generate a file filtered.svg containing the comparisons of the selected tests.
The -f and -s options can be used/omitted independently. If both are omitted, a single perf.svg
will be produced covering the full input test set. Additionally, their effects can be combined by providing a third -c
option (this will produce 2 files filtered-top.svg and filtered-bot.svg instead of 3). An optional key -o can be
supplied to specify an output directory for the generated files.
There is also a legacy script scripts/plot-performance/chart_perf.sh that can be used to generate comparison charts
in both svg and png formats. It requires gnuplot to run and assumes both files contain
the same test set. The following command will produce two files perf.svg and perf.png in the current directory.
$ scripts/plot-performance/chart_perf.sh path_to_before_summary.csv path_to_after_summary.csv
The current formatting is optimized for comparing some subsets of the full test run, typically just the benchmarks alone. If one wishes to save time or is not interested in top speedups/slowdowns, the benchmark subset can be obtained by running
$ scripts/test/test_plugin.sh \
benchmark-stitch-lh \
benchmark-bytestring \
benchmark-vector-algorithms \
benchmark-cse230 \
benchmark-esop2013 \
benchmark-icfp15-pos \
benchmark-icfp15-neg
Miscelaneous tasks
- Profiling See the instructions in scripts/profiling-driver/ProfilingDriver.hs.
- Getting stack traces on exceptions See
-xcflag in the GHC user's guide. - Working with submodules See
man gitsubmodulesor the git documentation site.
GHC support policy
LH supports only one version of GHC at any given time. This is because LH depends heavily on the ghc library
and there is currently no distinction between public API's and API's internal to GHC. There are currently no
release notes for the ghc library and breaking changes happen without notice and without deprecation
periods. Supporting only one GHC version saves developer time because it obviates the need for #ifdef's
throughout the codebase, or for an compatibility layer that becomes increasingly difficult to write as we
attempt to support more GHC versions. Porting to newer GHC versions takes less time, the code is easier to
read and there is less code duplication.
Users of older versions of GHC can still use
