How does it work?

GHC is a mighty optimizing compiler, and the centerpiece of optimizing, the
simplifier is capable of quite a bit of symbolic execution. We can use this
to prove program equalities, simply by taking two expressions, letting GHC
simplify them as far as possible. If the resulting expressions are the same,
then the original expressions are – as far as the compiler is concerned –
identicial.

The GHC simplifier works on the level of the intermediate language GHC Core,
and failed proofs will be reported as such.

The gory details are as follows: The simplifier is run 8 times, twice for each
of the simplifier phases 4, 3, 2 and 1. In between, the occurrence analiser
is run. Near the end, we also run common-subexpression elimination.

The simplifier is run with more aggressive flags. In particular, it is
instructed to inline functions aggressively and without worrying about code
size.

Why is this so great?

You can annotate your code with proofs, in the same file, in the same
language, without extra tools (besides the plugin).

The proofs stay with the code and are run with every compilation.

The proof goes through when the compiler thinks the expressions are the
same. There is no worry about whether an external proof tools captures the
semantics of GHC’s Haskell precisely.

It suports, in principle, all of Haskell’s syntax, including a huge number
of extensions.

It is super easy (if it works).

Using rewrite rules allows proofs with regard to some theory (e.g. with
regard to equations about foldr and other list combinators), independent
of whether these are proven.

Why is this not so great?

It can only prove quite simple things right now.

Even for easy things, the proof might fail because GHC simply simplifies the
expressions slightly different, and there is not always an easy way of
fixing this.

The proofs depend on optimization flags.

There is no guarantee that the next GHC release will be able to prove the
same things.

Failed proofs are reported in GHC Core instead of Haskell.

At least currently, it more or less requires GHC HEAD (it compiles with
GHC-8.0, but it has less control over the simplifier and less proofs will go
through.)

But note that these apply to your whole module, and are exported from it, so you
should not attempt to add such a rule to the same module where you prove
the rule. And if you don’t want these rules to be applied in normal code,
put your proofs into a separate Proof module that is never imported.

Shall I use this in production?

You can try. It certainly does not hurt, and proofs that go through are fine.
It might not prove enough to be really useful.

What next?

It remains to be seen how useful this approach really is, and what can be done
to make it more useful. So we need to start proving some things.

Here are some aspects that likely need to be improved:

The user should be put into control of some of the simplifier settings.
Depending on the proof, one might want to go through more or less of the
simplifier phases, or disable and enable certain rules.

Maybe a syntax that does not abuse term-level bindings can be introduced.
Currently, though, this is not possible for a plugin.

If deemed useful, this functionaly maybe can become part of GHC, and the
simplifier could get a few extra knobs to turn.

A custom function to compare expressions that relates more than just
alpha-equivalence could expand the scope of this plugin.

The reporting of failed proofs can be improved.

Come up with a better story about recursive functions.

How else can I prove things about Haskell?

Wait for full dependent types in Haskell and express your equivalences as
types.

Manually or mechanically (e.g. using Haskabelle) rewrite your code in a
theorem prover such as Isabelle,
Agda or
Coq, and prove stuff there.

Write your code in these theorem provers in the first place and export them
to Haskell.

You might be able to prove a few things using
Liquid Haskell or,
actually quite similar to this, HERMIT.

Can I comment or help?

Sure! We can use the GitHub issue tracker for discussions, and obviously
contributions are welcome.