nomeata’s mind shares
http://www.joachim-breitner.de//blog
Joachim Breitners Denkblogadehttp://joachim-breitner.de/avatars/avatar_128.pngnomeata’s mind shares
http://www.joachim-breitner.de//blog
128128Proof reuse in Coq using existential variables
http://www.joachim-breitner.de/blog/740-Proof_reuse_in_Coq_using_existential_variables
http://www.joachim-breitner.de/blog/740-Proof_reuse_in_Coq_using_existential_variableshttp://www.joachim-breitner.de/blog/740-Proof_reuse_in_Coq_using_existential_variables#commentsmail@joachim-breitner.de (Joachim Breitner)<p>This is another technical post that is only of interest only to Coq users.</p>
<p>TL;DR: Using existential variable for hypotheses allows you to easily refactor a complicated proof into an induction schema and the actual proofs.</p>
<h3 id="setup">Setup</h3>
<p>As a running example, I will use a small theory of “bags”, which you can think of as lists represented as trees, to allow an <span class="math inline"><em>O</em>(1)</span> append operation:</p>
<pre><code>Require Import Coq.Arith.Arith.
Require Import Psatz.
Require FunInd.
(* The data type *)
Inductive Bag a : Type :=
| Empty : Bag a
| Unit : a -> Bag a
| Two : Bag a -> Bag a -> Bag a.
Arguments Empty {_}.
Arguments Unit {_}.
Arguments Two {_}.
Fixpoint length {a} (b : Bag a) : nat :=
match b with
| Empty => 0
| Unit _ => 1
| Two b1 b2 => length b1 + length b2
end.
(* A smart constructor that ensures that a [Two] never
has [Empty] as subtrees. *)
Definition two {a} (b1 b2 : Bag a) : Bag a := match b1 with
| Empty => b2
| _ => match b2 with | Empty => b1
| _ => Two b1 b2 end end.
Lemma length_two {a} (b1 b2 : Bag a) :
length (two b1 b2) = length b1 + length b2.
Proof. destruct b1, b2; simpl; lia. Qed.
(* A first non-trivial function *)
Function take {a : Type} (n : nat) (b : Bag a) : Bag a :=
if n =? 0
then Empty
else match b with
| Empty => b
| Unit x => b
| Two b1 b2 => two (take n b1) (take (n - length b1) b2)
end.</code></pre>
<h3 id="the-theorem">The theorem</h3>
<p>The theorem that I will be looking at in this proof describes how <code>length</code> and <code>take</code> interact:</p>
<pre><code>Theorem length_take''':
forall {a} n (b : Bag a),
length (take n b) = min n (length b).</code></pre>
<p>Before I dive into it, let me point out that this example itself is too simple to warrant the techniques that I will present in this post. I have to rely on your imagination to scale this up to appreciate the effect on significantly bigger proofs.</p>
<h3 id="naive-induction">Naive induction</h3>
<p>How would we go about proving this lemma? Surely, <a href="https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.induction"><code>induction</code></a> is the way to go! And indeed, this is provable using induction (on the <code>Bag</code>) just fine:</p>
<pre><code>Proof.
intros.
revert n.
induction b; intros n.
* simpl.
destruct (Nat.eqb_spec n 0).
+ subst. rewrite Nat.min_0_l. reflexivity.
+ rewrite Nat.min_0_r. reflexivity.
* simpl.
destruct (Nat.eqb_spec n 0).
+ subst. rewrite Nat.min_0_l. reflexivity.
+ simpl. lia.
* simpl.
destruct (Nat.eqb_spec n 0).
+ subst. rewrite Nat.min_0_l. reflexivity.
+ simpl. rewrite length_two, IHb1, IHb2. lia.
Qed.</code></pre>
<p>But there is a problem: A proof by induction on the <code>Bag</code> argument immediately creates three subgoals, one for each constructor. But that is not how <code>take</code> is defined, which <em>first</em> checks the value of <code>n</code>, independent of the constructor. This means that we have to do the case-split and the proof for the case <code>n = 0</code> three times, although they are identical. It’s a one-line proof here, but imagine something bigger...</p>
<h3 id="proof-by-fixpoint">Proof by fixpoint</h3>
<p>Can we refactor the proof to handle the case <code>n = 0</code> first? Yes, but not with a simple invocation of the <code>induction</code> tactic. We could do well-founded induction on the <code>length</code> of the argument, or we can do the proof using the more primitive <a href="https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.fix"><code>fix</code> tactic</a>. The latter is a bit hairy, you won’t know if your proof is accepted until you do <code>Qed</code> (or check with <a href="https://coq.inria.fr/refman/proof-engine/proof-handling.html#coq:cmd.guarded"><code>Guarded</code></a>), but when it works it can yield some nice proofs.</p>
<pre><code>Proof.
intros a.
fix IH 2.
intros.
rewrite take_equation.
destruct (Nat.eqb_spec n 0).
+ subst n. rewrite Nat.min_0_l. reflexivity.
+ destruct b.
* rewrite Nat.min_0_r. reflexivity.
* simpl. lia.
* simpl. rewrite length_two, !IH. lia.
Qed.</code></pre>
<p>Nice: we eliminated the duplication of proofs!</p>
<h3 id="a-functional-induction-lemma">A functional induction lemma</h3>
<p>Again, imagine that we jumped through more hoops here ... maybe some well-founded recursion with a tricky size measure and complex proofs that the measure decreases ... or maybe you need to carry around an invariant about your arguments and you have to work hard to satisfy the assumption of the induction hypothesis.</p>
<p>As long as you do only one proof about <code>take</code>, that is fine. As soon as you do a second proof, you will notice that you have to repeat all of that, and it can easily make up most of your proof...</p>
<p>Wouldn’t it be nice if you can do the common parts of the proofs only once, obtain a generic proof scheme that you can use for (most) proofs about <code>take</code>, and then just fill in the blanks?</p>
<p>Incidentally, the <a href="https://coq.inria.fr/refman/language/gallina-extensions.html#coq:cmd.function"><code>Function</code> command</a> provides precisely that:</p>
<pre><code>take_ind
: forall (a : Type) (P : nat -> Bag a -> Bag a -> Prop),
(forall (n : nat) (b : Bag a), (n =? 0) = true -> P n b Empty) ->
(forall (n : nat) (b : Bag a), (n =? 0) = false -> b = Empty -> P n Empty b) ->
(forall (n : nat) (b : Bag a), (n =? 0) = false -> forall x : a, b = Unit x -> P n (Unit x) b) ->
(forall (n : nat) (b : Bag a),
(n =? 0) = false ->
forall b1 b2 : Bag a,
b = Two b1 b2 ->
P n b1 (take n b1) ->
P (n - length b1) b2 (take (n - length b1) b2) ->
P n (Two b1 b2) (two (take n b1) (take (n - length b1) b2))) ->
forall (n : nat) (b : Bag a), P n b (take n b)</code></pre>
<p>which is great if you can use <code>Function</code> (although not perfect – we’d rather see <code>n = 0</code> instead of <code>(n =? 0) = true</code>), but often <code>Function</code> is not powerful enough to define the function you care about.</p>
<h3 id="extracting-the-scheme-from-a-proof">Extracting the scheme from a proof</h3>
<p>We could define our own <code>take_ind'</code> by hand, but that is a lot of work, and we may not get it right easily, and when we change out functions, there is now this big proof statement to update.</p>
<p>Instead, let us use existentials, which are variables where Coq infers their type from how we use them, so we don’t have to declare them. Unfortunately, Coq does not support writing just</p>
<pre><code>Lemma take_ind':
forall (a : Type) (P : nat -> Bag a -> Bag a -> Prop),
forall (IH1 : ?) (IH2 : ?) (IH3 : ?) (IH4 : ?),
forall n b, P n b (take n b).</code></pre>
<p>where we just leave out the type of the assumptions (Isabelle does...), but we can fake it using some generic technique.</p>
<p>We begin with stating an auxiliary lemma using a sigma type to say “there exist some assumption that are sufficient to show the conclusion”:</p>
<pre><code>Lemma take_ind_aux:
forall a (P : _ -> _ -> _ -> Prop),
{ Hs : Prop |
Hs -> forall n (b : Bag a), P n b (take n b)
}.</code></pre>
<p>We use the [<code>eexist</code> tactic])(https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacv.eexists) (existential <code>exists</code>) to construct the sigma type without committing to the type of <code>Hs</code> yet.</p>
<pre><code>Proof.
intros a P.
eexists.
intros Hs.</code></pre>
<p>This gives us an assumption <code>Hs : ?Hs</code> – note the existential type. We need four of those, which we can achieve by writing</p>
<pre><code> pose proof Hs as H1. eapply proj1 in H1. eapply proj2 in Hs.
pose proof Hs as H2. eapply proj1 in H2. eapply proj2 in Hs.
pose proof Hs as H3. eapply proj1 in H3. eapply proj2 in Hs.
rename Hs into H4.</code></pre>
<p>we now have this goal state:</p>
<pre><code>1 subgoal
a : Type
P : nat -> Bag a -> Bag a -> Prop
H4 : ?Goal2
H1 : ?Goal
H2 : ?Goal0
H3 : ?Goal1
______________________________________(1/1)
forall (n : nat) (b : Bag a), P n b (take n b)</code></pre>
<p>At this point, we start reproducing the proof of <code>length_take</code>: The same approach to induction, the same case splits:</p>
<pre><code> fix IH 2.
intros.
rewrite take_equation.
destruct (Nat.eqb_spec n 0).
+ subst n.
revert b.
refine H1.
+ rename n0 into Hnot_null.
destruct b.
* revert n Hnot_null.
refine H2.
* rename a0 into x.
revert x n Hnot_null.
refine H3.
* assert (IHb1 : P n b1 (take n b1)) by apply IH.
assert (IHb2 : P (n - length b1) b2 (take (n - length b1) b2)) by apply IH.
revert n b1 b2 Hnot_null IHb1 IHb2.
refine H4.
Defined. (* Important *)</code></pre>
<p>Inside each case, we move all relevant hypotheses into the goal using <a href="https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.revert"><code>revert</code></a> and <a href="https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.refine"><code>refine</code></a> with the corresponding assumption, thus instantiating it. In the recursive case (<code>Two</code>), we assert that <code>P</code> holds for the subterms, by induction.</p>
<p>It is important to end this proofs with <a href="https://coq.inria.fr/refman/proof-engine/vernacular-commands.html#vernac-controlling-the-reduction-strategies"><code>Defined</code>, and not <code>Qed</code>,</a> as we will see later.</p>
<p>In a next step, we can remove the sigma type:</p>
<pre><code>Definition take_ind' a P := proj2_sig (take_ind_aux a P).</code></pre>
<p>The type of <code>take_ind'</code> is as follows:</p>
<pre><code>take_ind'
: forall (a : Type) (P : nat -> Bag a -> Bag a -> Prop),
proj1_sig (take_ind_aux a P) ->
forall n b, P n b (take n b)</code></pre>
<p>This looks almost like an induction lemma. The assumptions of this lemma have the not very helpful type <code>proj1_sig (take_ind_aux a P)</code>, but we can already use this to prove <code>length_take</code>:</p>
<pre><code>Theorem length_take:
forall {a} n (b : Bag a),
length (take n b) = min n (length b).
Proof.
intros a.
intros.
apply take_ind' with (P := fun n b r => length r = min n (length b)).
repeat apply conj; intros.
* rewrite Nat.min_0_l. reflexivity.
* rewrite Nat.min_0_r. reflexivity.
* simpl. lia.
* simpl. rewrite length_two, IHb1, IHb2. lia.
Qed.</code></pre>
<p>In this case I have to explicitly state <code>P</code> where I invoke <code>take_ind'</code>, because Coq cannot figure out this instantiation on its own (it requires higher-order unification, which is undecidable and unpredictable). In other cases I had more luck.</p>
<p>After I <code>apply take_ind'</code>, I have this proof goal:</p>
<pre><code>______________________________________(1/1)
proj1_sig (take_ind_aux a (fun n b r => length r = min n (length b)))</code></pre>
<p>which is the type that Coq inferred for <code>Hs</code> above. We know that this is a conjunction of a bunch of assumptions, and we can split it as such, using <code>repeat apply conj</code>. At this point, Coq needs to look inside <code>take_ind_aux</code>; this would fail if we used <code>Qed</code> to conclude the proof of <code>take_ind_aux</code>.</p>
<p>This gives me four goals, one for each case of <code>take</code>, and the remaining proofs really only deals with the specifics of <code>length_take</code> – no more general dealing with worrying about getting the induction right and doing the case-splitting the right way.</p>
<p>Also note that, very conveniently, Coq uses the same name for the induction hypotheses <code>IHb1</code> and <code>IHb2</code> that we used in <code>take_ind_aux</code>!</p>
<h3 id="making-it-prettier">Making it prettier</h3>
<p>It may be a bit confusing to have this <code>proj1_sig</code> in the type, especially when working in a team where others will use your induction lemma without knowing its internals. But we can resolve that, and also turn the conjunctions into normal arrows, using a bit of tactic support. This is completely generic, so if you follow this procedure, you can just copy most of that:</p>
<pre><code>Lemma uncurry_and: forall {A B C}, (A /\ B -> C) -> (A -> B -> C).
Proof. intros. intuition. Qed.
Lemma under_imp: forall {A B C}, (B -> C) -> (A -> B) -> (A -> C).
Proof. intros. intuition. Qed.
Ltac iterate n f x := lazymatch n with
| 0 => x
| S ?n => iterate n f uconstr:(f x)
end.
Ltac uncurryN n x :=
let n' := eval compute in n in
lazymatch n' with
| 0 => x
| S ?n => let uc := iterate n uconstr:(under_imp) uconstr:(uncurry_and) in
let x' := uncurryN n x in
uconstr:(uc x')
end.</code></pre>
<p>With this in place, we can define our final proof scheme lemma:</p>
<pre><code>Definition take_ind'' a P
:= ltac:(let x := uncurryN 3 (proj2_sig (take_ind_aux a P)) in exact x).
Opaque take_ind''.</code></pre>
<p>The type of <code>take_ind''</code> is now exactly what we’d wish for: All assumptions spelled out, and the <code>n =? 0</code> already taken of (compare this to the <code>take_ind</code> provided by the <code>Function</code> command above):</p>
<pre><code>take_ind''
: forall (a : Type) (P : nat -> Bag a -> Bag a -> Prop),
(forall b : Bag a, P 0 b Empty) ->
(forall n : nat, n <> 0 -> P n Empty Empty) ->
(forall (x : a) (n : nat), n <> 0 -> P n (Unit x) (Unit x)) ->
(forall (n : nat) (b1 b2 : Bag a),
n <> 0 ->
P n b1 (take n b1) ->
P (n - length b1) b2 (take (n - length b1) b2) ->
P n (Two b1 b2) (two (take n b1) (take (n - length b1) b2))) ->
forall (n : nat) (b : Bag a), P n b (take n b)</code></pre>
<p>At this point we can mark <code>take_ind''</code> as <code>Opaque</code>, to hide how we obtained this lemma.</p>
<p>Our proof does not change a lot; we merely no longer have to use <code>repeat apply conj</code>:</p>
<pre><code>Theorem length_take''':
forall {a} n (b : Bag a),
length (take n b) = min n (length b).
Proof.
intros a.
intros.
apply take_ind'' with (P := fun n b r => length r = min n (length b)); intros.
* rewrite Nat.min_0_l. reflexivity.
* rewrite Nat.min_0_r. reflexivity.
* simpl. lia.
* simpl. rewrite length_two, IHb1, IHb2. lia.
Qed.</code></pre>
<h3 id="is-it-worth-it">Is it worth it?</h3>
<p>It was in my case: <a href="https://github.com/antalsz/hs-to-coq/compare/de89fd0...b5b8ff7">Applying this trick</a> in our ongoing work of verifying parts of the Haskell compiler GHC separated a somewhat proof into a re-usable proof scheme (<code>go_ind</code>), making the actual proofs (<code>go_all_WellScopedFloats</code>, <code>go_res_WellScoped</code>) much neater and to the point. It saved “only” 60 lines (if I don’t count the 20 “generic” lines above), but the pay-off will increase as I do even more proofs about this function.</p>Fri, 18 May 2018 08:51:19 -0400Avoid the dilemma of the trailing comma
http://www.joachim-breitner.de/blog/739-Avoid_the_dilemma_of_the_trailing_comma
http://www.joachim-breitner.de/blog/739-Avoid_the_dilemma_of_the_trailing_commahttp://www.joachim-breitner.de/blog/739-Avoid_the_dilemma_of_the_trailing_comma#commentsmail@joachim-breitner.de (Joachim Breitner)<p>The Haskell syntax uses comma-separated lists in various places and does, in contrast to other programming language, not allow a trailing comma. If everything goes on one line you write</p>
<pre><code> (foo, bar, baz)</code></pre>
<p>and everything is nice.</p>
<h3 id="lining-up">Lining up</h3>
<p>But if you want to have one entry on each line, then the obvious plan</p>
<pre><code> (foo,
bar,
baz
)</code></pre>
<p>is aesthetically unpleasing and moreover, extending the list by <em>one</em> to</p>
<pre><code> (foo,
bar,
baz,
quux
)</code></pre>
<p>modifies <em>two</em> lines, which produces less pretty diffs.</p>
<p>Because it is much more common to append to lists rather than to prepend, Haskellers have developed the idiom of leading comma:</p>
<pre><code> ( foo
, bar
, baz
, quux
)</code></pre>
<p>which looks strange until you are used to it, but solves the problem of appending to a list. And we see this idiom in many places:</p>
<ul>
<li><p>In Cabal files:</p>
<pre><code> build-depends: base >= 4.3 && < 5
, array
, deepseq >= 1.2 && < 1.5</code></pre></li>
<li><p>In module headers:</p>
<pre><code>{-# LANGUAGE DefaultSignatures
, EmptyCase
, ExistentialQuantification
, FlexibleContexts
, FlexibleInstances
, GADTs
, InstanceSigs
, KindSignatures
, RankNTypes
, ScopedTypeVariables
, TemplateHaskell
, TypeFamilies
, TypeInType
, TypeOperators
, UndecidableInstances #-}</code></pre></li>
</ul>
<h3 id="think-outside-the-list">Think outside the list!</h3>
<p>I started to avoid this pattern where possible. And it is possible everywhere instead of having a declaration with a list, you can just have multiple declarations. I.e.:</p>
<ul>
<li><p>In Cabal files:</p>
<pre><code> build-depends: base >= 4.3 && < 5
build-depends: array
build-depends: deepseq >= 1.2 && < 1.5</code></pre></li>
<li><p>In module headers:</p>
<pre><code>{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}</code></pre></li>
</ul>
<p>It is a bit heavier, but it has a number of advantages:</p>
<ol style="list-style-type: decimal">
<li>Both appending and prepending works without touching other lines.</li>
<li>It is visually more homogeneous, making it – despite the extra words – easier to spot mistakes visually.</li>
<li>You can easily sort the declarations alphabetically with your editor.</li>
<li>Especially in <code>Cabal</code> files: If you have syntax error in your dependency specification (which I always have, writing <code><<</code> instead of <code><</code> due to my Debian background), <code>cabal</code> will actually give you a helpful error location – it always only tells you which <code>build-depends</code> stanza was wrong, so if you have only one, then <a href="https://stackoverflow.com/q/32751149/946226">that’s not helpful</a>.</li>
</ol>
<h3 id="what-when-it-does-not-work">What when it does not work?</h3>
<p>Unfortunately, not every list in Haskell can have that treatment, and that’s why <a href="https://github.com/ghc-proposals/ghc-proposals/pull/87">the recent GHC proposal on <code>ExtraCommas</code></a> wants to lift the restriction. In particular, it wants to allow trailing commas in subexport lists:</p>
<pre><code>module Foo
( Foo(
A,
B,
),
fromFoo,
)</code></pre>
<p>(Weirdly, export lists already allow trailing commas). An alternative here might be to write</p>
<pre><code>module Foo
( Foo(A),
Foo(B),
fromFoo,
)</code></pre>
<p>and teach the compiler to not warn about the duplicate export of the <code>Foo</code> type.</p>
<p>For plain lists, this idiom can be useful:</p>
<pre><code>list :: [Int]
list = let (>>) = (++) in do
[ 1 ]
[ 2 ]
[ 3 ]
[ 4 ]</code></pre>
<p>It requires <code>RebindableSyntax</code>, so I do not recommend it for regular code, but it can be useful in a module that is dedicated to hold some generated data or configuration. And of course it works with any binary operator, not just <code>(++)</code></p>Mon, 30 Apr 2018 22:19:47 -0400Verifying local definitions in Coq
http://www.joachim-breitner.de/blog/738-Verifying_local_definitions_in_Coq
http://www.joachim-breitner.de/blog/738-Verifying_local_definitions_in_Coqhttp://www.joachim-breitner.de/blog/738-Verifying_local_definitions_in_Coq#commentsmail@joachim-breitner.de (Joachim Breitner)<p>TL;DR: We can give top-level names to local definitions, so that we can state and prove stuff about them without having to rewrite the programs.</p>
<h3 id="when-a-haskeller-writes-coq">When a Haskeller writes Coq</h3>
<p>Imagine you teach Coq to a Haskell programmer, and give them the task of pairing each element in a list with its index. The Haskell programmer might have</p>
<pre><code>addIndex :: [a] -> [(Integer, a)]
addIndex xs = go 0 xs
where go n [] = []
go n (x:xs) = (n,x) : go (n+1) xs</code></pre>
<p>in mind and write this Gallina function (Gallina is the programming language of Coq):</p>
<pre><code>Require Import Coq.Lists.List.
Import ListNotations.
Definition addIndex {a} (xs : list a) : list (nat * a) :=
let fix go n xs := match xs with
| [] => []
| x::xs => (n, x) :: go (S n) xs
end
in go 0 xs.</code></pre>
<p>Alternatively, imagine you are using <a href="https://github.com/antalsz/hs-to-coq"><code>hs-to-coq</code></a> to mechanically convert the Haskell definition into Coq.</p>
<h3 id="when-a-coq-user-tries-to-verify-that">When a Coq user tries to verify that</h3>
<p>Now your task is to prove something about this function, for example</p>
<pre><code>Theorem addIndex_spec:
forall {a} n (xs : list a),
nth n (map fst (addIndex xs)) n = n.</code></pre>
<p>If you just have learned Coq, you will think “I can do this, this surely holds by induction on <code>xs</code>.” But if you have a bit more experience, you will already see a problem with this (if you do not see the problem yet, I encourage you to stop reading, copy the few lines above, and try to prove it).</p>
<p>The problem is that – as so often – you have to generalize the statement for the induction to go through. The theorem as stated says something about <code>addIndex</code> or, in other words, about <code>go 0</code>. But in the inductive case, you will need some information about <code>go 1</code>. In fact, you need a lemma like this:</p>
<pre><code>Lemma go_spec:
forall {a} n m k (xs : list a), k = n + m ->
nth n (map fst (go m xs)) k = k.</code></pre>
<p>But <code>go</code> is not a (top-level) function! How can we fix that?</p>
<ul>
<li>We can try to awkwardly work-around not having a name for <code>go</code> in our proofs, and essentially prove <code>go_spec</code> inside the proof of <code>addIndex_spec</code>. Might work in this small case, but does not scale up to larger proofs.</li>
<li>We can ask the programmer to avoid using local functions, and first define <code>go</code> as a top-level fixed point. But maybe we don’t want to bother them because of that. (Or, more likely, we are using <code>hs-to-coq</code> and that tool stubbornly tries to make the output as similar to the given Haskell code as possible.)</li>
<li>We can copy’n’paste the definition of <code>go</code> and make a separate, after-the-fact top-level definition. But this is not nice from a maintenance point of view: If the code changes, we have to update this copy.</li>
<li>Or we apply this one weird trick...</li>
</ul>
<h3 id="the-weird-trick">The weird trick</h3>
<p>We can define <code>go</code> after-the-fact, but instead of copy’n’pasting the definition, we can use Coq’s tactics to define it. Here it goes:</p>
<pre><code>Definition go {a} := ltac:(
let e := eval cbv beta delta [addIndex] in (@addIndex a []) in
(* idtac e; *)
lazymatch e with | let x := ?def in _ =>
exact def
end).</code></pre>
<p>Let us take it apart:</p>
<ol style="list-style-type: decimal">
<li>We define <code>go</code>, and give the parameters that <code>go</code> depends upon. Note that of the two parameters of <code>addIndex</code>, the definition of <code>go</code> only depends on (“captures”) <code>a</code>, but not <code>xs</code>.</li>
<li>We do <em>not</em> give a type to <code>go</code>. We could, but that would again just be copying information that is already there.</li>
<li>We define go via an <code>ltac</code> expression: Instead of a term we give a tactic that calculates the term.</li>
<li>This tactic first binds <code>e</code> to the body of <code>addIndex</code>. To do so, it needs to pass enough arguments to <code>addIndex</code>. The concrete value of the list argument does not matter, so we pass <code>[]</code>. The term <code>@addIndex a []</code> is now evaluated with the evaluation flags <code>eval cbv beta delta [addIndex]</code>, which says “unfold <code>addIndex</code> and do beta reduction, but nothing else”. In particularly, we do not do <code>zeta</code> reduction, which would reduce the <code>let go := …</code> definition. (The <a href="https://coq.inria.fr/refman/proof-engine/tactics.html#performing-computations">user manual</a> very briefly describes these flags.)</li>
<li>The <code>idtac e</code> line can be used to peek at <code>e</code>, for example when the next tactic fails. We can use this to check that <code>e</code> really is of the form <code>let fix go := … in …</code>.</li>
<li>The <code>lazymatch</code> line matches <code>e</code> against the pattern <code>let x := ?def in _</code>, and binds the definition of <code>go</code> to the name <code>def</code>.</li>
<li>And the <code>exact def</code> tactic tells Coq to use <code>def</code> as the definition of <code>go</code>.</li>
</ol>
<p>We now have defined <code>go</code>, of type <code>go : forall {a}, nat -> list a -> list (nat * a)</code>, and can state and prove the auxiliary lemma:</p>
<pre><code>Lemma go_spec:
forall {a} n m k (xs : list a), k = n + m ->
nth n (map fst (go m xs)) k = k.
Proof.
intros ?????.
revert n m k.
induction xs; intros; destruct n; subst; simpl.
1-3:reflexivity.
apply IHxs; lia.
Qed.</code></pre>
<p>When we come to the theorem about <code>addIndex</code>, we can play a little trick with <code>fold</code> to make the proof goal pretty:</p>
<pre><code>Theorem addIndex_spec:
forall {a} n (xs : list a),
nth n (map fst (addIndex xs)) n = n.
Proof.
intros.
unfold addIndex.
fold (@go a).
(* goal here: nth n (map fst (go 0 xs)) n = n *)
apply go_spec; lia.
Qed.</code></pre>
<h3 id="multiple-local-definitions">Multiple local definitions</h3>
<p>The trick extends to multiple local definitions, but needs some extra considerations to ensure that terms are closed. A bit contrived, but let us assume that we have this function definition:</p>
<pre><code>Definition addIndex' {a} (xs : list a) : list (nat * a) :=
let inc := length xs in
let fix go n xs := match xs with
| [] => []
| x::xs => (n, x) :: go (inc + n) xs
end in
go 0 xs.</code></pre>
<p>We now want to give names to <code>inc</code> <em>and</em> to <code>go</code>. I like to use a section to collect the common parameters, but that is not essential here. The trick above works flawlessly for `inc':</p>
<pre><code>Section addIndex'.
Context {a} (xs : list a).
Definition inc := ltac:(
let e := eval cbv beta delta [addIndex'] in (@addIndex' a xs) in
lazymatch e with | let x := ?def in _ =>
exact def
end).</code></pre>
<p>But if we try it for <code>go'</code>, like such:</p>
<pre><code>Definition go' := ltac:(
let e := eval cbv beta delta [addIndex'] in (@addIndex' a xs) in
lazymatch e with | let x := _ in let y := ?def in _ =>
exact def
end).</code></pre>
<p>we get “Ltac variable def depends on pattern variable name x which is not bound in current context”. To fix this, we use higher-order pattern matchin (<code>@?def</code>) to substitute “our” <code>inc</code> for the local <code>inc</code>:</p>
<pre><code>Definition go' := ltac:(
let e := eval cbv beta delta [addIndex'] in (@addIndex' a xs) in
lazymatch e with | let x := _ in let y := @?def x in _ =>
let def' := eval cbv beta in (def inc) in
exact def'
end).</code></pre>
<p>instead. We have now defined both <code>inc</code> and <code>go'</code> and can use them in proofs about <code>addIndex'</code>:</p>
<pre><code>Theorem addIndex_spec':
forall n, nth n (map fst (addIndex' xs)) n = n * length xs.
Proof.
intros.
unfold addIndex'.
fold inc go'. (* order matters! *)
(* goal here: nth n (map fst (go' 0 xs)) n = n * inc *)</code></pre>
<h3 id="reaching-into-a-match">Reaching into a match</h3>
<p>This trick also works when the local definition we care about is inside a match statement. Consider:</p>
<pre><code>Definition addIndex_weird {a} (oxs : option (list a))
:= match oxs with
| None => []
| Some xs =>
let fix go n xs := match xs with
| [] => []
| x::xs => (n, x) :: go (S n) xs
end in
go 0 xs
end.
Definition go_weird {a} := ltac:(
let e := eval cbv beta match delta [addIndex_weird]
in (@addIndex_weird a (Some [])) in
idtac e;
lazymatch e with | let x := ?def in _ =>
exact def
end).</code></pre>
<p>Note the addition of <code>match</code> to the list of evaluation flags passed to <code>cbv</code>.</p>
<h3 id="conclusion">Conclusion</h3>
<p>While local definitions are idiomatic in Haskell (in particular thanks to the <code>where</code> syntax), they are usually avoided in Coq, because they get in the way of verification. If, for some reason, one is stuck with such definitions, then this trick presents a reasonable way out.</p>Sun, 22 Apr 2018 17:47:24 -0400The magic “Just do it” type class
http://www.joachim-breitner.de/blog/735-The_magic_%E2%80%9CJust_do_it%E2%80%9D_type_class
http://www.joachim-breitner.de/blog/735-The_magic_%E2%80%9CJust_do_it%E2%80%9D_type_classhttp://www.joachim-breitner.de/blog/735-The_magic_%E2%80%9CJust_do_it%E2%80%9D_type_class#commentsmail@joachim-breitner.de (Joachim Breitner)<p>One of the great strengths of strongly typed functional programming is that it allows <em>type driven development</em>. When I have some non-trivial function to write, I first write its type signature, and then the writing the implementation often very obvious.</p>
<h3 id="once-more-i-am-feeling-silly">Once more, I am feeling silly</h3>
<p>In fact, it often is completely mechanical. Consider the following function:</p>
<div class="sourceCode"><pre class="sourceCode hs"><code class="sourceCode haskell"><span class="ot">foo ::</span> (r <span class="ot">-></span> <span class="dt">Either</span> e a) <span class="ot">-></span> (a <span class="ot">-></span> (r <span class="ot">-></span> <span class="dt">Either</span> e b)) <span class="ot">-></span> (r <span class="ot">-></span> <span class="dt">Either</span> e (a,b))</code></pre></div>
<p>This is somewhat like the bind for a combination of the error monad and the reader monad, and remembers the intermediate result, but that doesn’t really matter now. What matters is that once I wrote that type signature, I feel silly having to also write the code, because there isn’t really anything interesting about that.</p>
<p>Instead, I’d like to tell the compiler to just do it for me! I want to be able to write</p>
<div class="sourceCode"><pre class="sourceCode hs"><code class="sourceCode haskell"><span class="ot">foo ::</span> (r <span class="ot">-></span> <span class="dt">Either</span> e a) <span class="ot">-></span> (a <span class="ot">-></span> (r <span class="ot">-></span> <span class="dt">Either</span> e b)) <span class="ot">-></span> (r <span class="ot">-></span> <span class="dt">Either</span> e (a,b))
foo <span class="fu">=</span> justDoIt</code></pre></div>
<p>And now I can! Assuming I am using GHC HEAD (or eventually GHC 8.6), I can run <a href="https://hackage.haskell.org/package/ghc-justdoit"><code>cabal install ghc-justdoit</code></a>, and then the following code actually works:</p>
<div class="sourceCode"><pre class="sourceCode hs"><code class="sourceCode haskell"><span class="ot">{-# OPTIONS_GHC -fplugin=GHC.JustDoIt.Plugin #-}</span>
<span class="kw">import </span><span class="dt">GHC.JustDoIt</span>
<span class="ot">foo ::</span> (r <span class="ot">-></span> <span class="dt">Either</span> e a) <span class="ot">-></span> (a <span class="ot">-></span> (r <span class="ot">-></span> <span class="dt">Either</span> e b)) <span class="ot">-></span> (r <span class="ot">-></span> <span class="dt">Either</span> e (a,b))
foo <span class="fu">=</span> justDoIt</code></pre></div>
<h3 id="what-is-this-justdoit">What is this <code>justDoIt</code>?</h3>
<pre><code>*GHC.LJT GHC.JustDoIt> :browse GHC.JustDoIt
class JustDoIt a
justDoIt :: JustDoIt a => a
(…) :: JustDoIt a => a</code></pre>
<p>Note that there are no instances for the <code>JustDoIt</code> class -- they are created, on the fly, by the GHC plugin <code>GHC.JustDoIt.Plugin</code>. During type-checking, it looks as these <code>JustDoIt t</code> constraints and tries to construct a term of type <code>t</code>. It is based on <a href="https://rd.host.cs.st-andrews.ac.uk/publications/jsl57.pdf">Dyckhoff’s LJT proof search</a> in intuitionistic propositional calculus, which I have <a href="https://github.com/nomeata/ghc-justdoit/blob/master/GHC/LJT.hs">implemented to work directly on GHC’s types and terms</a> (and I find it pretty slick). Those who like Unicode can write <code>(…)</code> instead.</p>
<h3 id="what-is-supported-right-now">What is supported right now?</h3>
<p>Because I am working directly in GHC’s representation, it is pretty easy to support user-defined data types and newtypes. So it works just as well for</p>
<div class="sourceCode"><pre class="sourceCode hs"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Result</span> a b <span class="fu">=</span> <span class="dt">Failure</span> a <span class="fu">|</span> <span class="dt">Success</span> b
<span class="kw">newtype</span> <span class="dt">ErrRead</span> r e a <span class="fu">=</span> <span class="dt">ErrRead</span> {<span class="ot"> unErrRead ::</span> r <span class="ot">-></span> <span class="dt">Result</span> e a }
<span class="ot">foo2 ::</span> <span class="dt">ErrRead</span> r e a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">ErrRead</span> r e b) <span class="ot">-></span> <span class="dt">ErrRead</span> r e (a,b)
foo2 <span class="fu">=</span> (…)</code></pre></div>
<p>It doesn’t infer coercions or type arguments or any of that fancy stuff, and carefully steps around anything that looks like it might be recursive.</p>
<h3 id="how-do-i-know-that-it-creates-a-sensible-implementation">How do I know that it creates a sensible implementation?</h3>
<p>You can check the generated Core using <code>-ddump-simpl</code> of course. But it is much more convenient to use <a href="https://github.com/nomeata/inspection-testing"><code>inspection-testing</code></a> to test such things, as I am doing in the <a href="https://github.com/nomeata/ghc-justdoit/blob/master/examples/Demo.hs">Demo file</a>, which you can skim to see a few more examples of <code>justDoIt</code> in action. I very much enjoyed reaping the benefits of the work I put into <code>inspection-testing</code>, as this is so much more convenient than manually checking the output.</p>
<h3 id="is-this-for-real-should-i-use-it">Is this for real? Should I use it?</h3>
<p>Of course you are welcome to play around with it, and it will not launch any missiles, but at the moment, I consider this a prototype that I created for two purposes:</p>
<ul>
<li><p>To demonstrates that you can use type checker plugins for program synthesis. Depending on what you need, this might allow you to provide a smoother user experience than the alternatives, which are:</p>
<ul>
<li>Preprocessors</li>
<li>Template Haskell</li>
<li>Generic programming together with type-level computation (e.g. <a href="http://hackage.haskell.org/package/generic-lens">generic-lens</a>)</li>
<li>GHC Core-to-Core plugins</li>
</ul>
<p>In order to make this viable, I <a href="http://git.haskell.org/ghc.git/commit/0e022e56b130ab9d277965b794e70d8d3fb29533">slightly changed the API</a> for type checker plugins, which are now free to produce arbitrary Core terms as they solve constraints.</p></li>
<li><p>To advertise the idea of taking type-driven computation to its logical conclusion and free users from having to implement functions that they have already specified sufficiently precisely by their type.</p></li>
</ul>
<h3 id="what-needs-to-happen-for-this-to-become-real">What needs to happen for this to become real?</h3>
<p>A bunch of things:</p>
<ul>
<li>The LJT implementation is somewhat neat, but I probably did not implement backtracking properly, and there might be more bugs.</li>
<li>The implementation is very much unoptimized.</li>
<li>For this to be practically useful, the user needs to be able to use it with confidence. In particular, the user should be able to predict what code comes out. If there a multiple possible implementations, i.e. a clear specification which implementations are more desirable than others, and it should probably fail if there is ambiguity.</li>
<li>It ignores any recursive type, so it cannot do anything with lists. It would be much more useful if it could do some best-effort thing here as well.</li>
</ul>
<p>If someone wants to pick it up from here, that’d be great!</p>
<h3 id="i-have-seen-this-before">I have seen this before…</h3>
<p>Indeed, the idea is not new.</p>
<p>Most famously in the Haskell work is certainly Lennart Augustssons’s <a href="http://hackage.haskell.org/package/djinn">Djinn</a> tool that creates Haskell source expression based on types. Alejandro Serrano has connected that to GHC in the library <a href="http://hackage.haskell.org/package/djinn-ghc">djinn-ghc</a>, but I coudn’t use this because it was still outputting Haskell source terms (and it is easier to re-implement LJT rather than to implement type inference).</p>
<p>Lennart Spitzner’s <a href="http://hackage.haskell.org/package/exference">exference</a> is a much more sophisticated tool that also takes library API functions into account.</p>
<p>In the Scala world, Sergei Winitzki very recently presented the pretty neat <a href="https://github.com/Chymyst/curryhoward">curryhoward</a> library that uses for Scala macros. He seems to have some good ideas about ordering solutions by likely desirability.</p>
<p>And in Idris, Joomy Korkut has created <a href="https://github.com/joom/hezarfen">hezarfen</a>.</p>Fri, 02 Feb 2018 14:01:11 -0500Finding bugs in Haskell code by proving it
http://www.joachim-breitner.de/blog/734-Finding_bugs_in_Haskell_code_by_proving_it
http://www.joachim-breitner.de/blog/734-Finding_bugs_in_Haskell_code_by_proving_ithttp://www.joachim-breitner.de/blog/734-Finding_bugs_in_Haskell_code_by_proving_it#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Last week, I wrote a small nifty tool called <a href="https://github.com/nomeata/bisect-binary"><code>bisect-binary</code></a>, which semi-automates answering the question “To what extent can I fill this file up with zeroes and still have it working”. I wrote it it in Haskell, and part of the Haskell code, in the <a href="https://github.com/nomeata/bisect-binary/blob/48f9b9f05509a8b0c15c654f790fefd4e0c22676/src/Intervals.hs">Intervals.hs</a> module, is a data structure for “subsets of a file” represented as a sorted list of intervals:</p>
<pre><code>data Interval = I { from :: Offset, to :: Offset }
newtype Intervals = Intervals [Interval]</code></pre>
<p>The code is the kind of Haskell code that I like to write: A small local recursive function, a few guards to case analysis, and I am done:</p>
<pre><code>intersect :: Intervals -> Intervals -> Intervals
intersect (Intervals is1) (Intervals is2) = Intervals $ go is1 is2
where
go _ [] = []
go [] _ = []
go (i1:is1) (i2:is2)
-- reorder for symmetry
| to i1 < to i2 = go (i2:is2) (i1:is1)
-- disjoint
| from i1 >= to i2 = go (i1:is1) is2
-- subset
| to i1 == to i2 = I f' (to i2) : go is1 is2
-- overlapping
| otherwise = I f' (to i2) : go (i1 { from = to i2} : is1) is2
where f' = max (from i1) (from i2)</code></pre>
<p>But clearly, the code is already complicated enough so that it is easy to make a mistake. I could have put in some QuickCheck properties to test the code, I was in proving mood...</p>
<h3 id="now-available-formal-verification-for-haskell">Now available: Formal Verification for Haskell</h3>
<p>Ten months ago I complained that there was <a href="http://www.joachim-breitner.de/blog/717-Why_prove_programs_equivalent_when_your_compiler_can_do_that_for_you_">no good way to verify Haskell code</a> (and created the nifty hack <a href="https://github.com/nomeata/ghc-proofs"><code>ghc-proofs</code></a>). But things have changed since then, as a group at UPenn (mostly Antal Spector-Zabusky, Stephanie Weirich and myself) has created <a href="https://github.com/antalsz/hs-to-coq"><code>hs-to-coq</code></a>: a translator from Haskell to the theorem prover Coq.</p>
<p>We have used <code>hs-to-coq</code> on various examples, as described in our <a href="https://arxiv.org/abs/1711.09286">CPP'18 paper</a>, but it is high-time to use it for real. The easiest way to use <code>hs-to-coq</code> at the moment is to clone the repository, copy one of the example directories (e.g. <code>examples/successors</code>), place the Haskell file to be verified there and put the right module name into the <code>Makefile</code>. I also commented out parts of the Haskell file that would drag in non-base dependencies.</p>
<h3 id="massaging-the-translation">Massaging the translation</h3>
<p>Often, <code>hs-to-coq</code> translates Haskell code without a hitch, but sometimes, a bit of help is needed. In this case, I had to specify <a href="https://github.com/antalsz/hs-to-coq/blob/8f84d61093b7be36190142c795d6cd4496ef5aed/examples/intervals/edits">three so-called <em>edits</em></a>:</p>
<ul>
<li><p>The Haskell code uses <code>Intervals</code> both as a name for a type and for a value (the constructor). This is fine in Haskell, which has separate value and type namespaces, but not for Coq. The line</p>
<pre><code>rename value Intervals.Intervals = ival</code></pre>
<p>changes the constructor name to <code>ival</code>.</p></li>
<li><p>I use the <code>Int64</code> type in the Haskell code. The Coq version of Haskell’s base library that comes with <code>hs-to-coq</code> does not support that yet, so I change that via</p>
<pre><code>rename type GHC.Int.Int64 = GHC.Num.Int</code></pre>
<p>to the normal <code>Int</code> type, which itself is mapped to <a href="https://coq.inria.fr/library/Coq.Numbers.BinNums.html">Coq’s <code>Z</code> type</a>. This is not a perfect fit, and my verification would not catch problems that arise due to the boundedness of <code>Int64</code>. Since none of my code does arithmetic, only comparisons, I am fine with that.</p></li>
<li><p>The biggest hurdle is the recursion of the local <code>go</code> functions. Coq requires all recursive functions to be obviously (i.e. structurally) terminating, and the <code>go</code> above is not. For example, in the first case, the arguments to <code>go</code> are simply swapped. It is very much not obvious why this is not an infinite loop.</p>
<p>I can specify a termination measure, i.e. a function that takes the arguments <code>xs</code> and <code>ys</code> and returns a “size” of type <code>nat</code> that decreases in every call: Add the lengths of <code>xs</code> and <code>ys</code>, multiply by two and add one if the the first interval in <code>xs</code> ends before the first interval in <code>ys</code>.</p>
<p>If the problematic function were a top-level function I could tell <code>hs-to-coq</code> about this termination measure and it would use this information to define the function using <code>Program Fixpoint</code>.</p>
<p>Unfortunately, <code>go</code> is a local function, so this mechanism is not available to us. If I care more about the verification than about preserving the exact Haskell code, I could easily change the Haskell code to make <code>go</code> a top-level function, but in this case I did not want to change the Haskell code.</p>
<p>Another way out offered by <code>hs-to-coq</code> is to translate the recursive function using an axiom <code>unsafeFix : forall a, (a -> a) -> a</code>. This looks scary, but as I explain in the previous blog post, <a href="http://www.joachim-breitner.de/blog/733-Existence_and_Termination">this axiom can be used in a safe way</a>.</p>
<p>I should point out it is my dissenting opinion to consider this a valid verification approach. The official stand of the <code>hs-to-coq</code> author team is that using <code>unsafeFix</code> in the verification can only be a temporary state, and eventually you’d be expected to fix (heh) this, for example by moving the functions to the top-level and using <code>hs-to-coq</code>’s the support for <code>Program Fixpoint</code>.</p></li>
</ul>
<p>With these edits in place, <code>hs-to-coq</code> splits out a faithful Coq copy of my Haskell code.</p>
<h3 id="time-to-prove-things">Time to prove things</h3>
<p>The rest of the work is mostly straight-forward use of Coq. I define the invariant I expect to hold for these lists of intervals, namely that they are sorted, non-empty, disjoint and non-adjacent:</p>
<pre><code>Fixpoint goodLIs (is : list Interval) (lb : Z) : Prop :=
match is with
| [] => True
| (I f t :: is) => (lb <= f)%Z /\ (f < t)%Z /\ goodLIs is t
end.
Definition good is := match is with
ival is => exists n, goodLIs is n end.</code></pre>
<p>and I give them meaning as Coq type for sets, <a href="https://coq.inria.fr/library/Coq.Sets.Ensembles.html"><code>Ensemble</code></a>:</p>
<pre><code>Definition range (f t : Z) : Ensemble Z :=
(fun z => (f <= z)%Z /\ (z < t)%Z).
Definition semI (i : Interval) : Ensemble Z :=
match i with I f t => range f t end.
Fixpoint semLIs (is : list Interval) : Ensemble Z :=
match is with
| [] => Empty_set Z
| (i :: is) => Union Z (semI i) (semLIs is)
end.
Definition sem is := match is with
ival is => semLIs is end.</code></pre>
<p>Now I prove for every function that it preserves the invariant and that it corresponds to the, well, corresponding function, e.g.:</p>
<pre><code>Lemma intersect_good : forall (is1 is2 : Intervals),
good is1 -> good is2 -> good (intersect is1 is2).
Proof. … Qed.
Lemma intersection_spec : forall (is1 is2 : Intervals),
good is1 -> good is2 ->
sem (intersect is1 is2) = Intersection Z (sem is1) (sem is2).
Proof. … Qed.</code></pre>
<p>Even though I punted on the question of termination while defining the functions, I do not get around that while verifying this, so I formalize the termination argument above</p>
<pre><code>Definition needs_reorder (is1 is2 : list Interval) : bool :=
match is1, is2 with
| (I f1 t1 :: _), (I f2 t2 :: _) => (t1 <? t2)%Z
| _, _ => false
end.
Definition size2 (is1 is2 : list Interval) : nat :=
(if needs_reorder is1 is2 then 1 else 0) + 2 * length is1 + 2 * length is2.</code></pre>
<p>and use it in my inductive proofs.</p>
<p>As I intend this to be a write-once proof, I happily copy’n’pasted proof scripts and did not do any cleanup. Thus, the <a href="https://github.com/antalsz/hs-to-coq/blob/8f84d61093b7be36190142c795d6cd4496ef5aed/examples/intervals/Proofs.v">resulting Proof file</a> is big, ugly and repetitive. I am confident that judicious use of Coq tactics could greatly condense this proof.</p>
<h3 id="using-program-fixpoint-after-the-fact">Using Program Fixpoint after the fact?</h3>
<p>This proofs are also an experiment of how I can actually do induction over a locally defined recursive function without too ugly proof goals (hence the line <code>match goal with [ |- context [unsafeFix ?f _ _] ] => set (u := f) end.</code>). One could improve upon this approach by following these steps:</p>
<ol style="list-style-type: decimal">
<li><p>Define copies (say, <code>intersect_go_witness</code>) of the local <code>go</code> using <code>Program Fixpoint</code> with the above termination measure. The termination argument needs to be made only once, here.</p></li>
<li><p>Use this function to prove that the argument <code>f</code> in <code>go = unsafeFix f</code> actually has a fixed point:</p>
<pre><code>Lemma intersect_go_sound:</code></pre>
<p>f intersect_go_witness = intersect_go_witness</p>
<p>(This requires functional extensionality). This lemma indicates that my use of the axioms <code>unsafeFix</code> and <code>unsafeFix_eq</code> are actually sound, as discussed in the previous blog post.</p></li>
<li><p>Still prove the desired properties for the <code>go</code> that uses <code>unsafeFix</code>, as before, but using the <a href="https://coq.inria.fr/refman/schemes.html#sec655">functional induction scheme</a> for <code>intersect_go</code>! This way, the actual proofs are free from any noisy termination arguments.</p>
<p>(The trick to define a recursive function just to throw away the function and only use its induction rule is one I learned in Isabelle, and is very useful to separate the meat from the red tape in complex proofs. Note that the induction rule for a function does not actually mention the function!)</p></li>
</ol>
<p>Maybe I will get to this later.</p>
<p><strong>Update:</strong> I experimented a bit in that direction, and it does not quite work as expected. In step 2 I am stuck because <code>Program Fixpoint</code> does not create a fixpoint-unrolling lemma, and in step 3 I do not get the induction scheme that I was hoping for. Both problems <a href="https://stackoverflow.com/a/46995609/946226">would not exist if I use the <code>Function</code> command</a>, although that needs some tickery to support a termination measure on multiple arguments. The induction lemma is not quite as polished as I was hoping for, so <a href="https://github.com/antalsz/hs-to-coq/blob/b7efc7a8dbacca384596fc0caf65e62e87ef2768/examples/intervals/Proofs_Function.v">he resulting proof</a> is still somewhat ugly, and it requires copying code, which does not scale well.</p>
<h3 id="efforts-and-gains">Efforts and gains</h3>
<p>I spent exactly 7 hours working on these proofs, according to <a href="http://arbtt.nomeata.de/"><code>arbtt</code></a>. I am sure that writing these functions took me much less time, but I cannot calculate that easily, as they were originally in the <code>Main.hs</code> file of <code>bisect-binary</code>.</p>
<p>I did <a href="https://github.com/nomeata/bisect-binary/commit/48f9b9f05509a8b0c15c654f790fefd4e0c22676#diff-38999f20f11fe6a93fa194587e8ad507">find and fix three bugs</a>:</p>
<ul>
<li>The <code>intersect</code> function would not always retain the invariant that the intervals would be non-empty.</li>
<li>The <code>subtract</code> function would prematurely advance through the list intervals in the second argument, which can lead to a genuinely wrong result. (This occurred twice.)</li>
</ul>
<p><strong>Conclusion:</strong> Verification of Haskell code using Coq is now practically possible!</p>
<p><strong>Final rant:</strong> Why is the Coq standard library so incomplete (compared to, say, Isabelle’s) and requires me to prove <a href="https://github.com/antalsz/hs-to-coq/blob/8f84d61093b7be36190142c795d6cd4496ef5aed/examples/intervals/Ensemble_facts.v">so many lemmas about basic functions on <code>Ensembles</code></a>?</p>Tue, 05 Dec 2017 09:17:43 -0500Less parentheses
http://www.joachim-breitner.de/blog/730-Less_parentheses
http://www.joachim-breitner.de/blog/730-Less_parentheseshttp://www.joachim-breitner.de/blog/730-Less_parentheses#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Yesterday, at the <a href="http://conf.researchr.org/track/hiw-2017/hiw-2017">Haskell Implementers Workshop 2017</a> in Oxford, I gave a lightning talk titled ”syntactic musings”, where I presented three possibly useful syntactic features that one might want to add to a language like Haskell.</p>
<p>The talked caused quite some heated discussions, and since the Internet likes heated discussion, I will happily share these ideas with you</p>
<h3 id="context-aka.-sections">Context aka. Sections</h3>
<p>This is probably the most relevant of the three proposals. Consider a bunch of related functions, say <code>analyseExpr</code> and <code>analyseAlt</code>, like these:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">analyseExpr ::</span> <span class="dt">Expr</span> <span class="ot">-></span> <span class="dt">Expr</span>
analyseExpr (<span class="dt">Var</span> v) <span class="fu">=</span> change v
analyseExpr (<span class="dt">App</span> e1 e2) <span class="fu">=</span>
<span class="dt">App</span> (analyseExpr e1) (analyseExpr e2)
analyseExpr (<span class="dt">Lam</span> v e) <span class="fu">=</span> <span class="dt">Lam</span> v (analyseExpr flag e)
analyseExpr (<span class="dt">Case</span> scrut alts) <span class="fu">=</span>
<span class="dt">Case</span> (analyseExpr scrut) (analyseAlt <span class="fu"><$></span> alts)
<span class="ot">analyseAlt ::</span> <span class="dt">Alt</span> <span class="ot">-></span> <span class="dt">Alt</span>
analyseAlt (dc, pats, e) <span class="fu">=</span> (dc, pats, analyseExpr e)</code></pre></div>
<p>You have written them, but now you notice that you need to make them configurable, e.g. to do different things in the <code>Var</code> case. You thus add a parameter to all these functions, and hence an argument to every call:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">type</span> <span class="dt">Flag</span> <span class="fu">=</span> <span class="dt">Bool</span>
<span class="ot">analyseExpr ::</span> <span class="dt">Flag</span> <span class="ot">-></span> <span class="dt">Expr</span> <span class="ot">-></span> <span class="dt">Expr</span>
analyseExpr flag (<span class="dt">Var</span> v) <span class="fu">=</span> <span class="kw">if</span> flag <span class="kw">then</span> change1 v <span class="kw">else</span> change2 v
analyseExpr flag (<span class="dt">App</span> e1 e2) <span class="fu">=</span>
<span class="dt">App</span> (analyseExpr flag e1) (analyseExpr flag e2)
analyseExpr flag (<span class="dt">Lam</span> v e) <span class="fu">=</span> <span class="dt">Lam</span> v (analyseExpr (not flag) e)
analyseExpr flag (<span class="dt">Case</span> scrut alts) <span class="fu">=</span>
<span class="dt">Case</span> (analyseExpr flag scrut) (analyseAlt flag <span class="fu"><$></span> alts)
<span class="ot">analyseAlt ::</span> <span class="dt">Flag</span> <span class="ot">-></span> <span class="dt">Alt</span> <span class="ot">-></span> <span class="dt">Alt</span>
analyseAlt flag (dc, pats, e) <span class="fu">=</span> (dc, pats, analyseExpr flag e)</code></pre></div>
<p>I find this code problematic. The intention was: “<code>flag</code> is a parameter that an external caller can use to change the behaviour of this code, but when reading and reasoning about this code, <code>flag</code> should be considered constant.”</p>
<p>But this intention is neither easily visible nor enforced. And in fact, in the above code, <code>flag</code> does “change”, as <code>analyseExpr</code> passes something else in the <code>Lam</code> case. The idiom is indistinguishable from the <em>environment idiom</em>, where a <em>locally changing</em> environment (such as “variables in scope”) is passed around.</p>
<p>So we are facing exactly the same problem as when reasoning about a loop in an imperative program with mutable variables. And we (pure functional programmers) should know better: We cherish immutability! We want to bind our variables once and have them scope over everything we need to scope over!</p>
<p>The solution I’d like to see in Haskell is common in other languages (Gallina, Idris, Agda, Isar), and this is what it would look like here:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">type</span> <span class="dt">Flag</span> <span class="fu">=</span> <span class="dt">Bool</span>
section (<span class="ot">flag ::</span> <span class="dt">Flag</span>) <span class="kw">where</span>
<span class="ot"> analyseExpr ::</span> <span class="dt">Expr</span> <span class="ot">-></span> <span class="dt">Expr</span>
analyseExpr (<span class="dt">Var</span> v) <span class="fu">=</span> <span class="kw">if</span> flag <span class="kw">then</span> change1 v <span class="kw">else</span> change2v
analyseExpr (<span class="dt">App</span> e1 e2) <span class="fu">=</span>
<span class="dt">App</span> (analyseExpr e1) (analyseExpr e2)
analyseExpr (<span class="dt">Lam</span> v e) <span class="fu">=</span> <span class="dt">Lam</span> v (analyseExpr e)
analyseExpr (<span class="dt">Case</span> scrut alts) <span class="fu">=</span>
<span class="dt">Case</span> (analyseExpr scrut) (analyseAlt <span class="fu"><$></span> alts)
<span class="ot"> analyseAlt ::</span> <span class="dt">Alt</span> <span class="ot">-></span> <span class="dt">Alt</span>
analyseAlt (dc, pats, e) <span class="fu">=</span> (dc, pats, analyseExpr e)</code></pre></div>
<p>Now the intention is clear: Within a clearly marked block, <code>flag</code> is fixed and when reasoning about this code I do not have to worry that it might change. Either <em>all</em> variables will be passed to <code>change1</code>, or <em>all</em> to <code>change2</code>. An important distinction!</p>
<p>Therefore, inside the <code>section</code>, the type of <code>analyseExpr</code> does not mention <code>Flag</code>, whereas outside its type is <code>Flag -> Expr -> Expr</code>. This is a bit unusual, but not completely: You see precisely the same effect in a <code>class</code> declaration, where the type signature of the methods do not mention the class constraint, but outside the declaration they do.</p>
<p>Note that idioms like implicit parameters or the <code>Reader</code> monad do not give the guarantee that the parameter is (locally) constant.</p>
<p>More details can be found in the <a href="https://github.com/ghc-proposals/ghc-proposals/pull/40">GHC proposal</a> that I prepared, and I invite you to raise concern or voice support there.</p>
<p>Curiously, this problem must have bothered me for longer than I remember: I discovered that seven years ago, I wrote a Template Haskell based implementation of this idea in the <a href="http://hackage.haskell.org/package/seal-module"><code>seal-module</code></a> package!</p>
<h3 id="less-parentheses-1-bulleted-argument-lists">Less parentheses 1: Bulleted argument lists</h3>
<p>The next two proposals are all about removing parentheses. I believe that Haskell’s tendency to express complex code with no or few parentheses is one of its big strengths, as it makes it easier to visualy parse programs. A common idiom is to use the <code>$</code> operator to separate a function from a complex argument without parentheses, but it does not help when there are multiple complex arguments.</p>
<p>For that case I propose to steal an idea from the surprisingly successful markup language markdown, and use bulleted lists to indicate multiple arguments:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">foo ::</span> <span class="dt">Baz</span>
foo <span class="fu">=</span> bracket
• some complicated code
that is evaluated first
• other complicated code for later
• even more complicated code</code></pre></div>
<p>I find this very easy to visually parse and navigate.</p>
<p>It is actually possible to do this now, if one defines <code>(•) = id</code> with <code>infixl 0 •</code>. A dedicated syntax extension (<code>-XArgumentBullets</code>) is preferable:</p>
<ul>
<li>It only really adds readability if the bullets are nicely vertically aligned, which the compiler should enforce.</li>
<li>I would like to use <code>$</code> inside these complex arguments, and multiple operators of precedence 0 do not mix. (<code>infixl -1 •</code> would help).</li>
<li>It should be possible to nest these, and distinguish different nesting levers based on their indentation.</li>
</ul>
<h3 id="less-parentheses-1-whitespace-precedence">Less parentheses 1: Whitespace precedence</h3>
<p>The final proposal is the most daring. I am convinced that it improves readability and should be considered when creating a new language. As for Haskell, I am at the moment not proposing this as a language extension (but could be convinced to do so if there is enough positive feedback).</p>
<p>Consider this definition of append:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">(++) ::</span> [a] <span class="ot">-></span> [a] <span class="ot">-></span> [a]
[] <span class="fu">++</span> ys <span class="fu">=</span> ys
(x<span class="fu">:</span>xs) <span class="fu">++</span> ys <span class="fu">=</span> x <span class="fu">:</span> (xs<span class="fu">++</span>ys)</code></pre></div>
<p>Imagine you were explaining the last line to someone orally. How would you speak it? One common way to do so is to not read the parentheses out aloud, but rather speak parenthesised expression more quickly and add pauses otherwise.</p>
<p>We can do the same in syntax!</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">(++) ::</span> [a] <span class="ot">-></span> [a] <span class="ot">-></span> [a]
[] <span class="fu">++</span> ys <span class="fu">=</span> ys
x<span class="fu">:</span>xs <span class="fu">++</span> ys <span class="fu">=</span> x <span class="fu">:</span> xs<span class="fu">++</span>ys</code></pre></div>
<p>The rule is simple: <em>A sequence of tokens without any space is implicitly parenthesised.</em></p>
<p>The reaction I got in Oxford was horror and disgust. And that is understandable – we are very used to ignore spacing when parsing expressions (unless it is indentation, of course. Then we are no longer horrified, as our non-Haskell colleagues are when they see our code).</p>
<p>But I am convinced that once you let the rule sink in, you will have no problem parsing such code with ease, and soon even with greater ease than the parenthesised version. It is a very natural thing to look at the general structure, identify “compact chunks of characters”, mentally group them, and then go and separately parse the internals of the chunks and how the chunks relate to each other. More natural than first scanning everything for <code>(</code> and <code>)</code>, matching them up, building a mental tree, and then digging deeper.</p>
<p>Incidentally, there was a non-programmer present during my presentation, and while she did not openly contradict the dismissive groan of the audience, I later learned that she found this variant quite obvious to understand and more easily to read than the parenthesised code.</p>
<p>Some FAQs about this:</p>
<ul>
<li><em>What about an operator with space on one side but not on the other?</em> I’d simply forbid that, and hence enforce readable code.</li>
<li><em>Do operator sections still require parenthesis?</em> Yes, I’d say so.</li>
<li>Does this overrule operator precedence? Yes! <code>a * b+c == a * (b+c)</code>.</li>
<li><em>What is a token</em>? Good question, and I am not not decided. In particular: Is a parenthesised expression a single token? If so, then <code>(Succ a)+b * c</code> parses as <code>((Succ a)+b) * c</code>, otherwise it should probably simply be illegal.</li>
<li><em>Can we extend this so that one space binds tighter than two spaces, and so on?</em> Yes we can, but really, we should not.</li>
<li><em>This is incompatible with Agda’s syntax!</em> Indeed it is, and I really like Agda’s mixfix syntax. Can’t have everything.</li>
<li><em>Has this been done before?</em> I have not seen it in any language, but <a href="http://wall.org/~lewis/2013/10/25/whitespace-precedence.html">Lewis Wall</a> has blogged this idea before.</li>
</ul>
<p>Well, let me know what you think!</p>Sun, 10 Sep 2017 11:10:16 +0100Compose Conference talk video online
http://www.joachim-breitner.de/blog/729-Compose_Conference_talk_video_online
http://www.joachim-breitner.de/blog/729-Compose_Conference_talk_video_onlinehttp://www.joachim-breitner.de/blog/729-Compose_Conference_talk_video_online#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Three months ago, I gave a talk at the <a href="http://www.composeconference.org/2017/program/">Compose::Conference</a> in New York about how Chris Smith and I added the ability to create networked multi-user programs to the educational Haskell programming environment <a href="https://code.world/">CodeWorld</a>, and finally the recording of the talk is available <a href="https://www.youtube.com/watch?v=2kKvVe673MA">on YouTube</a> (and is being discussed <a href="https://www.reddit.com/r/haskell/comments/6uam49/compose_conference_lock_step_simulation_is_childs/">on reddit</a>):</p>
<iframe src="https://www.youtube.com/embed/2kKvVe673MA?rel=0?ecver=2" width="640" height="360" frameborder="0" style="display: block; margin-left: auto; margin-right: auto">
</iframe>
<p>It was the talk where I got the most positive feedback afterwards, and I think this is partly due to how I created the presentation: Instead of showing static slides, I programmed the complete visual display from scratch as an “interaction” within the CodeWorld environment, including all transitions, an working embedded game of Pong and a simulated multi-player environments with adjustable message delays. I have put the <a href="https://github.com/nomeata/codeworld-talk">code for the presentation</a> online.</p>
<p>Chris and I have written about this for ICFP'17, and thanks to open access I can actually share <a href="https://www.joachim-breitner.de/publications/CodeWorld-ICFP17.pdf">the paper</a> freely with you and under a CC license. If you come to Oxford you can see me perform a shorter version of this talk again.</p>Sun, 20 Aug 2017 20:50:10 +0200Communication Failure
http://www.joachim-breitner.de/blog/728-Communication_Failure
http://www.joachim-breitner.de/blog/728-Communication_Failurehttp://www.joachim-breitner.de/blog/728-Communication_Failure#commentsmail@joachim-breitner.de (Joachim Breitner)<p>I am still far from being a professor, but I recently got a glimpse of what awaits you in that role…</p>
<blockquote>
<p><strong>From:</strong> Sebastian R. <…<span class="citation">@gmail.com</span>><br/>
<strong>To:</strong> joachim@cis.upenn.edu<br/>
<strong>Subject:</strong> re: Errors</p>
<p>I've spotted a basic error in your course on Haskell (<a href="https://www.seas.upenn.edu/~cis194/fall16/" class="uri">https://www.seas.upenn.edu/~cis194/fall16/</a>). Before I proceed, it's cool if you're not receptive to errors being indicated; I've come across a number of professors who would rather take offense than admit we're all human and thus capable of making mistakes... My goal is to find a resource that might be useful well into the future, and a good indicator of that is how responsive the author is to change.</p>
<p>In your introduction note you have written:</p>
<blockquote>
<p>n contrast to a classical intro into Haskell, we do not start with numbers, booleans, tuples, lists and strings, but we start with pictures. These are of course library-defined (hence the input CodeWorld) and not part of “the language”. But that does not make them less interesting, and in fact, even the basic boolean type is library defined – it just happens to be the standard library.</p>
</blockquote>
<p>Howeverm there is no <code>input CodeWorld</code> in the code above. Have you been made aware of this error earlier?</p>
<p>Regards, ...</p>
</blockquote>
<p>Nice. I like when people learn from my lectures. The introduction is a bit werid, but ok, maybe this guy had some bad experiences.</p>
<p>Strangley, I don’t see a mistake in the material, so I respond:</p>
<blockquote>
<p><strong>From:</strong> Joachim Breitner <a href="mailto:joachim@cis.upenn.edu">joachim@cis.upenn.edu</a><br/>
<strong>To:</strong> Sebastian R. <…<span class="citation">@gmail.com</span>><br/>
<strong>Subject:</strong> Re: Errors</p>
<p>Dear Sebastian,</p>
<p>thanks for pointing out errors. But the first piece of code under “Basic Haskell” starts with</p>
<pre><code>{-# LANGUAGE OverloadedStrings #-}
import CodeWorld</code></pre>
<p>so I am not sure what you are referring to.</p>
<p>Note that these are lecture notes, so you have to imagine a lecturer editing code live on stage along with it. If you only have the notes, you might have to infer a few things.</p>
<p>Regards, Joachim</p>
</blockquote>
<p>A while later, I receive this response:</p>
<blockquote>
<p><strong>From:</strong> Sebastian R. <…<span class="citation">@gmail.com</span>><br/>
<strong>To:</strong> Joachim Breitner <a href="mailto:joachim@cis.upenn.edu">joachim@cis.upenn.edu</a><br/>
<strong>Subject:</strong> Re: Errors</p>
<p>Greetings, Joachim.</p>
<p>Kindly open the lecture slides and search for "input CodeWorld" to find the error; it is not in the code, but in the paragraph that implicitly refers back to the code.</p>
<p>You might note that I quoted this precisely from the lectures... and so I repeat myself... this came from <strong>your</strong> lectures; they're not my words!</p>
<blockquote>
<p>In contrast to a classical intro into Haskell, we do not start with numbers, booleans, tuples, lists and strings, but we start with pictures. These are of course library-defined (hence the <span style="color:red">input CodeWorld</span>) and not part of “the language”. But that does not make them less interesting, and in fact, even the basic boolean type is library defined – it just happens to be the standard library.</p>
</blockquote>
<p>This time around, I've highlighted the issue. I hope that made it easier for you to spot...</p>
<p>Nonetheless, I got my answer. Don't reply if you're going to fight tooth and nail about such a basic fix; it's simply a waste of both of our time. I'd rather learn from somewhere else...</p>
<p>On Tue, Aug 1, 2017 at 11:19 PM, Joachim Breitner <a href="mailto:joachim@cis.upenn.edu">joachim@cis.upenn.edu</a> wrote:<br/>
…</p>
</blockquote>
<p>I am a bit reminded of Sean Spicer … “they’re not my words!” … but clearly I am missing something. And indeed I am: In the code snippet, I wrote – correctly – <code>import CodeWorld</code>, but in the text I had <code>input CodeWorld</code>. I probably did write LaTeX before writing the lecture notes. Well, glad to have that sorted out. I fixed the mistake and wrote back:</p>
<blockquote>
<p><strong>From:</strong> Joachim Breitner <a href="mailto:joachim@cis.upenn.edu">joachim@cis.upenn.edu</a><br/>
<strong>To:</strong> Sebastian R. <…<span class="citation">@gmail.com</span>><br/>
<strong>Betreff:</strong> Re: Errors</p>
<p>Dear Sebastian,</p>
<p>nobody is fighting, and I see the mistake now: The problem is not that the line is not in the code, the problem is that there is a typo in the line and I wrote “input” instead of “import”.</p>
<p>Thanks for the report, although you did turn it into quite a riddle… a simple “you wrote import when it should have been import” would have been a better user of both our time.</p>
<p>Regards, Joachim</p>
<p>Am Donnerstag, den 03.08.2017, 13:32 +1000 schrieb Sebastian R.:<br/>
…</p>
</blockquote>
<p>(And it seems I now made the inverse typo, writing “import“ instead of “input”. Anyways, I did not think of this any more until a few days later, when I found this nice message in my mailbox:</p>
<blockquote>
<p><strong>From:</strong> Sebastian R. <…<span class="citation">@gmail.com</span>><br/>
<strong>To:</strong> Joachim Breitner <a href="mailto:joachim@cis.upenn.edu">joachim@cis.upenn.edu</a><br/>
<strong>Subject:</strong> Re: Errors</p>
<blockquote>
<p>a simple “you wrote import when it should have been import” would have been a better user of both our time.</p>
</blockquote>
<p>We're both programmers. How about I cut ALL of the unnecessary garbage and just tell you to s/import/input/ on that last quotation (the thing immediately before this paragraph, in case you didn't know).</p>
<p>I blatantly quoted the error, like this:</p>
<blockquote>
<p>In your introduction note you have written:</p>
<blockquote>
<p>n contrast to a classical intro into Haskell, we do not start with numbers, booleans, tuples, lists and strings, but we start with pictures. These are of course library-defined (hence the input CodeWorld) and not part of “the language”. But that does not make them less interesting, and in fact, even the basic boolean type is library defined – it just happens to be the standard library.</p>
</blockquote>
<p>Howeverm there is no <code>input CodeWorld</code> in the code above.</p>
</blockquote>
<p>Since that apparently wasn't clear enough, in my second email to you I had to highlight it like so:</p>
<blockquote>
<p>You might note that I quoted this precisely from the lectures... and so I repeat myself... this came from <strong>your</strong> lectures; they're not my words!</p>
<blockquote>
<p>In contrast to a classical intro into Haskell, we do not start with numbers, booleans, tuples, lists and strings, but we start with pictures. These are of course library-defined (hence the <span style="color:red">input CodeWorld</span>) and not part of “the language”. But that does not make them less interesting, and in fact, even the basic boolean type is library defined – it just happens to be the standard library.</p>
</blockquote>
<p>This time around, I've highlighted the issue. I hope that made it easier for you to spot...</p>
</blockquote>
<p>I'm not sure if you're memeing at me or not now, but it seems either your reading comprehension, or your logical deduction skills might be substandard. Unfortunately, there isn't much either of us can do about that, so I'm happy to accept that some people will be so stupid; after all, it's to be expected and if we don't accept that which is to be expected then we live our lives in denial.</p>
<p>Happy to wrap up this discusson here, Seb...</p>
<p>On Fri, Aug 4, 2017 at 12:22 AM, Joachim Breitner <a href="mailto:joachim@cis.upenn.edu">joachim@cis.upenn.edu</a> wrote:<br/>
…</p>
</blockquote>
<p>Well, I chose to be amused by this, and I am sharing my amusement with you.</p>Sun, 06 Aug 2017 11:14:05 -0400How is coinduction the dual of induction?
http://www.joachim-breitner.de/blog/727-How_is_coinduction_the_dual_of_induction_
http://www.joachim-breitner.de/blog/727-How_is_coinduction_the_dual_of_induction_http://www.joachim-breitner.de/blog/727-How_is_coinduction_the_dual_of_induction_#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Earlier today, I demonstrated how to work with <a href="http://www.joachim-breitner.de/blog/726-Coinduction_in_Coq_and_Isabelle">coinduction in the theorem provers Isabelle, Coq and Agda</a>, with a very simple example. This reminded me of a discussion I had in Karlsruhe with my then colleague Denis Lohner: If coinduction is the dual of induction, why do the induction principles look so different? I like what we observed there, so I’d like to share this.</p>
<p>The following is mostly based on my naive understanding of coinduction based on what I observe in <a href="http://isabelle.in.tum.de/dist/Isabelle2016-1/doc/datatypes.pdf">the implementation in Isabelle</a>. I am sure that a different, more categorial presentation of datatypes (as initial resp. terminal objects in some category of algebras) makes the duality more obvious, but that does not necessarily help the working Isabelle user who wants to make sense of coninduction.</p>
<h3 id="inductive-lists">Inductive lists</h3>
<p>I will use the usual polymorphic list data type as an example. So on the one hand, we have normal, finite inductive lists:</p>
<pre><code>datatype 'a list = nil | cons (hd : 'a) (tl : "'a list")</code></pre>
<p>with the well-known induction principle that many of my readers know by heart (syntax slightly un-isabellized):</p>
<pre><code>P nil → (∀x xs. P xs → P (cons x xs)) → ∀ xs. P xs</code></pre>
<h3 id="coinductive-lists">Coinductive lists</h3>
<p>In contrast, if we define our lists coinductively to get possibly infinite, Haskell-style lists, by writing</p>
<pre><code>codatatype 'a llist = lnil | lcons (hd : 'a) (tl : "'a llist")</code></pre>
<p>we get the following coinduction principle:</p>
<pre><code>(∀ xs ys.
R xs ys' → (xs = lnil) = (ys = lnil) ∧
(xs ≠ lnil ⟶ ys' ≠ lnil ⟶
hd xs = hd ys ∧ R (tl xs) (tl ys))) →
→ (∀ xs ys. R xs ys → xs = ys)</code></pre>
<p>This is less scary that it looks at first. It tell you “if you give me a relation <code>R</code> between lists which implies that either both lists are empty or both lists are nonempty, and furthermore if both are non-empty, that they have the same head and tails related by <code>R</code>, then any two lists related by <code>R</code> are actually equal.”</p>
<p>If you think of the infinte list as a series of states of a computer program, then this is nothing else than a <em>bisimulation</em>.</p>
<p>So we have two proof principles, both of which make intuitive sense. But how are they related? They look very different! In one, we have a predicate <code>P</code>, in the other a relation <code>R</code>, to point out just one difference.</p>
<h3 id="relation-induction">Relation induction</h3>
<p>To see how they are dual to each other, we have to recognize that both these theorems are actually specializations of a more general (co)induction principle.</p>
<p>The <code>datatype</code> declaration automatically creates a <em>relator</em>:</p>
<pre><code>rel_list :: ('a → 'b → bool) → 'a list → 'b list → bool</code></pre>
<p>The definition of <code>rel_list R xs ys</code> is that <code>xs</code> and <code>ys</code> have the same shape (i.e. length), and that the corresponding elements are pairwise related by <code>R</code>. You might have defined this relation yourself at some time, and if so, you probably introduced it as an inductive predicate. So it is not surprising that the following induction principle characterizes this relation:</p>
<pre><code>Q nil nil →
(∀x xs y ys. R x y → Q xs ys → Q (cons x xs) (cons y ys)) →
(∀xs ys → rel_list R xs ys → Q xs ys)</code></pre>
<p>Note how how similar this lemma is in shape to the normal induction for lists above! And indeed, if we choose <code>Q xs ys ↔ (P xs ∧ xs = ys)</code> and <code>R x y ↔ (x = y)</code>, then we obtain exactly that. In that sense, the relation induction is a generalization of the normal induction.</p>
<h3 id="relation-coinduction">Relation coinduction</h3>
<p>The same observation can be made in the coinductive world. Here, as well, the <code>codatatype</code> declaration introduces a function</p>
<pre><code>rel_llist :: ('a → 'b → bool) → 'a llist → 'b llist → bool</code></pre>
<p>which relates lists of the same shape with related elements – only that this one also relates infinite lists, and therefore is a coinductive relation. The corresponding rule for proof by coinduction is not surprising and should remind you of bisimulation, too:</p>
<pre><code>(∀xs ys.
R xs ys → (xs = lnil) = (ys = lnil) ∧
(xs ≠ lnil ⟶ ys ≠ lnil ⟶
Q (hd xs) (hd ys) ∧ R (tl xs) (tl ys))) →
(∀ xs ys → R xs ys → rel_llist Q xs ys)</code></pre>
<p>It is even more obvious that this is a generalization of the standard coinduction principle shown above: Just instantiate <code>Q</code> with equality, which turns <code>rel_llist Q</code> into equality on the lists, and you have the theorem above.</p>
<h3 id="the-duality">The duality</h3>
<p>With our induction and coinduction principle generalized to relations, suddenly a duality emerges: If you turn around the implication in the conclusion of one you get the conclusion of the other one. This is an example of “co<em>something</em> is <em>something</em> with arrows reversed”.</p>
<p>But what about the premise(s) of the rules? What happens if we turn around the arrow here? Although slighty less immediate, it turns out that they are the same as well. To see that, we start with the premise of the coinduction rule, reverse the implication and then show that to be equivalent to the two premises of the induction rule:</p>
<pre><code>(∀xs ys.
R xs ys ← (xs = lnil) = (ys = lnil) ∧
(xs ≠ lnil ⟶ ys ≠ lnil ⟶
Q (hd xs) (hd ys) ∧ R (tl xs) (tl ys)))
= { case analysis (the other two cases are vacuously true) }
(∀xs ys.
xs = lnil → ys = lnil →
R xs ys ← (xs = lnil) = (ys = lnil) ∧
(xs ≠ lnil ⟶ ys ≠ lnil ⟶
Q (hd xs) (hd ys) ∧ R (tl xs) (tl ys)))
∧ (∀xs ys.
xs ≠ lnil ⟶ ys ≠ lnil
R xs ys ← (xs = lnil) = (ys = lnil) ∧
(xs ≠ lnil ⟶ ys ≠ lnil ⟶
Q (hd xs) (hd ys) ∧ R (tl xs) (tl ys)))
= { simplification }
(∀xs ys. xs = lnil → ys = lnil → R xs ys
∧ (∀x xs y ys. R (cons x xs) (cons y ys) ← (Q x y ∧ R xs ys))
= { more rewriting }
R nil nil
∧ (∀x xs y ys. Q x y → R xs ys → R (cons x xs) (cons y ys))</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>The coinduction rule is not the direct dual of the induction rule, but both are specializations of more general, relational proof methods, where the duality is clearly present.</p>
<p>More generally, this little excursion shows that it is often beneficial to think of types less as sets, and more as relations – this way of thinking is surprisingly fruitful, and led to proofs of <a href="https://en.wikipedia.org/wiki/Parametricity">parametricity</a> and free theorems and other nice things.</p>Thu, 27 Jul 2017 22:05:32 -0400The perils of live demonstrations
http://www.joachim-breitner.de/blog/723-The_perils_of_live_demonstrations
http://www.joachim-breitner.de/blog/723-The_perils_of_live_demonstrationshttp://www.joachim-breitner.de/blog/723-The_perils_of_live_demonstrations#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Yesterday, I was giving a <a href="https://www.meetup.com/de-DE/haskellhackers/events/240759486/">talk at the The South SF Bay Haskell User Group</a> about how implementing lock-step simulation is trivial in Haskell and how Chris Smith and me are using this to make <a href="https://code.world/">CodeWorld</a> even more attractive to students. I gave the talk before, at <a href="http://www.composeconference.org/2017/program/">Compose::Conference</a> in New York City earlier this year, so I felt well prepared. On the flight to the West Coast I slightly extended the slides, and as I was too cheap to buy in-flight WiFi, I tested them only locally.</p>
<p>So I arrived at the offices of Target<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> in Sunnyvale, got on the WiFi, uploaded my slides, which are in fact one large interactive CodeWorld program, and tried to run it. But I got a type error…</p>
<p>Turns out that the API of CodeWorld was changed <a href="https://github.com/google/codeworld/commit/054c811b494746ec7304c3d495675046727ab114">just the day before</a>:</p>
<pre><code>commit 054c811b494746ec7304c3d495675046727ab114
Author: Chris Smith <cdsmith@gmail.com>
Date: Wed Jun 21 23:53:53 2017 +0000
Change dilated to take one parameter.
Function is nearly unused, so I'm not concerned about breakage.
This new version better aligns with standard educational usage,
in which "dilation" means uniform scaling. Taken as a separate
operation, it commutes with rotation, and preserves similarity
of shapes, neither of which is true of scaling in general.</code></pre>
<p>Ok, that was <a href="https://github.com/nomeata/codeworld-talk/commit/9a5830b0a20010a9e54ab23a6f4aeafd31fccc6b">quick to fix</a>, and the CodeWorld server started to compile my code, and compiled, and aborted. It turned out that my program, presumably the larges CodeWorld interaction out there, hit the time limit of the compiler.</p>
<p>Luckily, Chris Smith just arrived at the venue, and he emergency-bumped the compiler time limit. The program compiled and I could start my presentation.</p>
<p>Unfortunately, the biggest blunder was still awaiting for me. I came to the slide where two instances of pong are played over a simulated network, and my point was that the two instances are perfectly in sync. Unfortunately, they were not. I guess it did support my point that lock-step simulation can easily go wrong, but it really left me out in the rain there, and I could not explain it – I did not modify this code since New York, and there it worked flawless<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a>. In the end, I could save my face a bit by running the <a href="https://code.world/run.html?mode=haskell&dhash=DoE66gidx7VusA3qcMRI_hg">real pong game</a> against an attendee over the network, and no desynchronisation could be observed there.</p>
<p>Today I dug into it and it took me a while, and it turned out that the problem was not in CodeWorld, or the lock-step simulation code discussed in <a href="https://arxiv.org/abs/1705.09704">our paper about it</a>, but in the code in my presentation that simulated the delayed network messages; in some instances it would deliver the UI events in different order to the two simulated players, and hence cause them do something different. Phew.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>Yes, the retail giant. Turns out that they have a small but enthusiastic Haskell-using group in their IT department.<a href="#fnref1">↩</a></p></li>
<li id="fn2"><p>I hope the video is going to be online soon, then you can check for yourself.<a href="#fnref2">↩</a></p></li>
</ol>
</div>Fri, 23 Jun 2017 16:54:36 -0700ghc-proofs rules more now
http://www.joachim-breitner.de/blog/720-ghc-proofs_rules_more_now
http://www.joachim-breitner.de/blog/720-ghc-proofs_rules_more_nowhttp://www.joachim-breitner.de/blog/720-ghc-proofs_rules_more_now#commentsmail@joachim-breitner.de (Joachim Breitner)<p>A few weeks ago I blogged about an experiment of mine, where I <a href="/blog/717-Why_prove_programs_equivalent_when_your_compiler_can_do_that_for_you_.html.en">proved equalities of Haskell programs by (ab)using the GHC simplifier</a>. For more details, please see that post, or the <a href="https://www.youtube.com/watch?v=jcL4bp4FMUw&feature=youtu.be">video of my talk at the Zürich Haskell User Group</a>, but one reason why this approach has any chance of being useful is the compiler’s support for rewrite rules.</p>
<p>Rewrite rules are program equations that the programmer specifies in the source file, and which the compiler then applies, from left to right, whenever some intermediate code matches the left-hand side of the equation. One such rule, for example, is</p>
<pre><code>{-# RULES "foldr/nil" forall k z. foldr k z [] = z #-}</code></pre>
<p>taken right out of the standard library.</p>
<p>In my blog post I went through the algebraic laws that a small library of mine, <a href="http://hackage.haskell.org/package/successors-0.1/docs/Control-Applicative-Successors.html">successors</a>, should fulfill, and sure enough, once I got to more interesting proofs, they would not go through just like that. At that point I had to add additional rules to the file I was editing, which helped the compiler to finish the proofs. Some of these rules were simple like</p>
<pre><code>{-# RULES "mapFB/id" forall c. mapFB c (\x -> x) = c #-}
{-# RULES "foldr/nil" forall k n. GHC.Base.foldr k n [] = n #-}
{-# RULES "foldr/undo" forall xs. GHC.Base.foldr (:) [] xs = xs #-}</code></pre>
<p>and some are more intricate like</p>
<pre><code>{-# RULES "foldr/mapFB" forall c f g n1 n2 xs.
GHC.Base.foldr (mapFB c f) n1 (GHC.Base.foldr (mapFB (:) g) n2 xs)
= GHC.Base.foldr (mapFB c (f.g)) (GHC.Base.foldr (mapFB c f) n1 n2) xs
#-}</code></pre>
<p>But there is something fishy going on here: The <code>foldr/nil</code> rule is identical to a rule in the standard library! I should not have to add to my file that as I am proving things. So I knew that the GHC plugin, which I wrote to do these proofs, was doing something wrong, but I did not investigate for a while.</p>
<p>I returned to this problem recetly, and with the efficient and quick <a href="https://ghc.haskell.org/trac/ghc/ticket/13614">help of Simon Peyton Jones</a>, I learned what I was doing wrong.<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> After fixing it, I could remove all the simple rules from the files with my proofs. And to my surprise, I could remove the intricate rule as well!</p>
<p>So with this bug fixed, ghc-proofs is able to prove <em>all</em> the Functor, Applicative and Monad rules of the Succs functor <a href="https://github.com/nomeata/ghc-proofs/blob/ea17e78a98c20995b2de4f64a9eb4e299f6dcde4/examples/Successors.hs">without any additional rewrite rules</a>, as you can see in the example file! (I still have to strategically place <code>seq</code>s in a few places.)</p>
<p>That’s great, isn’t it! Yeah, sure. But having to introduce the rules at that point provided a very good narrative in my talk, so when I will give a similar talk next week in Pairs (actually, twice, first <a href="https://www.irif.fr/gt/acs/index">at the university</a> and then <a href="https://www.meetup.com/de-DE/haskell-paris/events/239389804/">at the Paris Haskell meetup</a>, I will have to come up with a different example that calls for additional rewrite rules.</p>
<p>In related news: Since the last blog post, ghc-proofs learned to interpret proof specifications like</p>
<pre><code>applicative_law4 :: Succs (a -> b) -> a -> Proof
applicative_law4 u y = u <*> pure y
=== pure ($ y) <*> u</code></pre>
<p>where it previously only understood</p>
<pre><code>applicative_law4 = (\ u (y::a) -> u <*> (pure y :: Succs a))
=== (\ u (y::a) -> pure ($ y) <*> u)
</code></pre>
<p>I am not sur if this should be uploaded to Hackage, but I invite you to play around with the <a href="https://github.com/nomeata/ghc-proofs">GitHub version of ghc-proofs</a>.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>In short: I did not initialize the simplifier with the right <code>InScopeSet</code>, so RULES about functions defined in the current module were not always applied, and I did not feed the <code>eps_rules</code> to the simplifier, which contains all the rules found in imported packages, such as <code>base</code>.<a href="#fnref1">↩</a></p></li>
</ol>
</div>Thu, 27 Apr 2017 23:11:38 -0400veggies: Haskell code generation from scratch
http://www.joachim-breitner.de/blog/719-veggies__Haskell_code_generation_from_scratch
http://www.joachim-breitner.de/blog/719-veggies__Haskell_code_generation_from_scratchhttp://www.joachim-breitner.de/blog/719-veggies__Haskell_code_generation_from_scratch#commentsmail@joachim-breitner.de (Joachim Breitner)<p>How hard it is to write a compiler for Haskell Core? Not too hard, actually!</p>
<p>I wish we had a formally verified compiler for Haskell, or at least for GHC’s intermediate language Core. Now formalizing that part of GHC itself seems to be far out of reach, with the many phases the code goes through (Core to STG to CMM to Assembly or LLVM) and optimizations happening at all of these phases and the many complicated details to the highly tuned GHC runtime (pointer tagging, support for concurrency and garbage collection).</p>
<h3 id="introducing-veggies">Introducing Veggies</h3>
<p>So to make that goal of a formally verified compiler more feasible, I set out and implemented code generation from GHC’s intermediate language Core to LLVM IR, with simplicity as the main design driving factor.</p>
<p>You can find the result in the <a href="https://github.com/nomeata/veggies">GitHub repository of <strong>veggies</strong></a> (the name derives from “verifiable GHC”). If you clone that and run <code>./boot.sh some-directory</code>, you will find that you can use the program <code>some-directory/bin/veggies</code> just like like you would use <code>ghc</code>. It comes with the full <code>base</code> library, so your favorite variant of HelloWorld might just compile and run.</p>
<p>As of now, the code generation handles all the Core constructs (which is easy when you simply ignore all the types). It supports a good number of primitive operations, including pointers and arrays – I implement these as need – and has support for FFI calls into C.</p>
<h3 id="why-you-dont-want-to-use-veggies">Why you don't want to use Veggies</h3>
<p>Since the code generator was written with simplicity in mind, performance of the resulting code is abysmal: Everything is boxed, i.e. represented as pointer to some heap-allocated data, including “unboxed” integer values and “unboxed” tuples. This is very uniform and simplifies the code, but it is also slow, and because there is no garbage collection (and probably never will be for this project), will fill up your memory quickly.</p>
<p>Also, the code is currently only supports 64bit architectures, and this is hard-coded in many places.</p>
<p>There is no support for concurrency.</p>
<h3 id="why-it-might-be-interesting-to-you-nevertheless">Why it might be interesting to you nevertheless</h3>
<p>So if it is not really usable to run programs with, should you care about it? Probably not, but maybe you do for one of these reasons:</p>
<ul>
<li>You always wondered how a compiler for Haskell actually works, and reading through a little over a thousands lines of code is less daunting than reading through the 34k lines of code that is GHC’s backend.</li>
<li>You have wacky ideas about Code generation for Haskell that you want to experiment with.</li>
<li>You have wacky ideas about Haskell that require special support in the backend, and want to prototype that.</li>
<li>You want to see how I use the GHC API to provide a <code>ghc</code>-like experience. (I copied GHC’s <code>Main.hs</code> and inserted a few hooks, an approach I copied from GHCJS).</li>
<li>You want to learn about running Haskell programs efficiently, and starting from veggies, you can implement all the trick of the trade yourself and enjoy observing the speed-ups you get.</li>
<li>You want to compile Haskell code to some weird platform that is supported by LLVM, but where you for some reason cannot run GHC’s runtime. (Because there are no threads and no garbage collection, the code generated by veggies does not require a runtime system.)</li>
<li>You want to formally verify Haskell code generation. Note that the code generator targets the same AST for LLVM IR that the <a href="https://github.com/vellvm/vellvm2/blob/master/src/coq/Ollvm_ast.v">vellvm2</a> project uses, so eventually, veggies can become a verified arrow in the top right corner <a href="https://deepspec.org/page/Research/">map of the DeepSpec project</a>.</li>
</ul>
<p>So feel free to play around with veggies, and report any issues you have on the GitHub repository.</p>Fri, 21 Apr 2017 11:30:27 -0400Why prove programs equivalent when your compiler can do that for you?
http://www.joachim-breitner.de/blog/717-Why_prove_programs_equivalent_when_your_compiler_can_do_that_for_you_
http://www.joachim-breitner.de/blog/717-Why_prove_programs_equivalent_when_your_compiler_can_do_that_for_you_http://www.joachim-breitner.de/blog/717-Why_prove_programs_equivalent_when_your_compiler_can_do_that_for_you_#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Last week, while working on <a href="http://code.world/">CodeWorld</a>, via a sequence of yak shavings, I ended up creating a nicely small library that provides <a href="http://hackage.haskell.org/package/successors/docs/Control-Applicative-Successors.html"><code>Control.Applicative.Succs</code></a>, a new applicative functor. And because I am trying to keep my Haskell karma good<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a>, I wanted to actually prove that my code fulfills the <code>Applicative</code> and <code>Monad</code> laws.</p>
<p>This led me to inserted writing long comments into my code, filled with lines like this:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="dt">The</span> second <span class="dt">Applicative</span> law<span class="fu">:</span>
pure (<span class="fu">.</span>) <span class="fu"><*></span> <span class="dt">Succs</span> u us <span class="fu"><*></span> <span class="dt">Succs</span> v vs <span class="fu"><*></span> <span class="dt">Succs</span> w ws
<span class="fu">=</span> <span class="dt">Succs</span> (<span class="fu">.</span>) [] <span class="fu"><*></span> <span class="dt">Succs</span> u us <span class="fu"><*></span> <span class="dt">Succs</span> v vs <span class="fu"><*></span> <span class="dt">Succs</span> w ws
<span class="fu">=</span> <span class="dt">Succs</span> (u <span class="fu">.</span>) (map (<span class="fu">.</span>) us) <span class="fu"><*></span> <span class="dt">Succs</span> v vs <span class="fu"><*></span> <span class="dt">Succs</span> w ws
<span class="fu">=</span> <span class="dt">Succs</span> (u <span class="fu">.</span> v) (map (<span class="fu">$</span>v) (map (<span class="fu">.</span>) us) <span class="fu">++</span> map (u <span class="fu">.</span>) vs) <span class="fu"><*></span> <span class="dt">Succs</span> w ws
<span class="fu">=</span> <span class="dt">Succs</span> (u <span class="fu">.</span> v) (map ((<span class="fu">$</span>v)<span class="fu">.</span>(<span class="fu">.</span>)) us <span class="fu">++</span> map (u <span class="fu">.</span>) vs) <span class="fu"><*></span> <span class="dt">Succs</span> w ws
<span class="fu">=</span> <span class="dt">Succs</span> ((u <span class="fu">.</span> v) w) (map (<span class="fu">$</span>w) (map ((<span class="fu">$</span>v)<span class="fu">.</span>(<span class="fu">.</span>)) us <span class="fu">++</span> map (u <span class="fu">.</span>) vs) <span class="fu">++</span> map (u<span class="fu">.</span>v) ws)
<span class="fu">=</span> <span class="dt">Succs</span> ((u <span class="fu">.</span> v) w) (map ((<span class="fu">$</span>w)<span class="fu">.</span>(<span class="fu">$</span>v)<span class="fu">.</span>(<span class="fu">.</span>)) us <span class="fu">++</span> map ((<span class="fu">$</span>w)<span class="fu">.</span>(u<span class="fu">.</span>)) vs <span class="fu">++</span> map (u<span class="fu">.</span>v) ws)
<span class="fu">=</span> <span class="dt">Succs</span> (u (v w)) (map (\u <span class="ot">-></span> u (v w)) us <span class="fu">++</span> map (\v <span class="ot">-></span> u (v w)) vs <span class="fu">++</span> map (\w <span class="ot">-></span> u (v w)) ws)
<span class="fu">=</span> <span class="dt">Succs</span> (u (v w)) (map (<span class="fu">$</span>(v w)) us <span class="fu">++</span> map u (map (<span class="fu">$</span>w) vs <span class="fu">++</span> map v ws))
<span class="fu">=</span> <span class="dt">Succs</span> u us <span class="fu"><*></span> <span class="dt">Succs</span> (v w) (map (<span class="fu">$</span>w) vs <span class="fu">++</span> map v ws)
<span class="fu">=</span> <span class="dt">Succs</span> u us <span class="fu"><*></span> (<span class="dt">Succs</span> v vs <span class="fu"><*></span> <span class="dt">Succs</span> w ws)</code></pre></div>
<p>Honk if you have done something like this before!</p>
<p>I proved all the laws, but I was very unhappy. I have a PhD on something about Haskell and theorem proving. I have worked with Isabelle, Agda and Coq. Both Haskell and theorem proving is decades old. And yet, I sit here, and tediously write manual proofs by hand. Is this really the best we can do?</p>
<p>Of course I could have taken my code, rewritten it in, say, Agda, and proved it correct there. But (right now) I don’t care about Agda code. I care about my Haskell code! I don’t want to write it twice, worry about copying mistakes and mismatchs in semantics, and have external proofs to maintain. Instead, I want to prove where I code, and have the proofs checked together with my code!</p>
<p>Then it dawned to me that this is, to some extent, possible. The Haskell compiler comes with a sophisticated program transformation machinery, which is meant to simplify and optimize code. But it can also be used to prove Haskell expressions to be equivalent! The idea is simple: Take two expressions, run both through the compiler’s simplifier, and check if the results are the same. If they are, then the expressions are, as far as the compiler is concerned, equivalent.</p>
<p>A handful of hours later, I was able to write proof tasks like</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">app_law_2 <span class="fu">=</span> (\ a b (<span class="ot">c::</span><span class="dt">Succs</span> a) <span class="ot">-></span> pure (<span class="fu">.</span>) <span class="fu"><*></span> a <span class="fu"><*></span> b <span class="fu"><*></span> c)
<span class="fu">===</span> (\ a b c <span class="ot">-></span> a <span class="fu"><*></span> (b <span class="fu"><*></span> c))</code></pre></div>
<p>and others into my source file, and the compiler would tell me happily:</p>
<pre><code>[1 of 1] Compiling Successors ( Successors.hs, Successors.o )
GHC.Proof: Proving getCurrent_proof1 …
GHC.Proof: Proving getCurrent_proof2 …
GHC.Proof: Proving getCurrent_proof3 …
GHC.Proof: Proving ap_star …
GHC.Proof: Proving getSuccs_proof1 …
GHC.Proof: Proving getSuccs_proof2 …
GHC.Proof: Proving getSuccs_proof3 …
GHC.Proof: Proving app_law_1 …
GHC.Proof: Proving app_law_2 …
GHC.Proof: Proving app_law_3 …
GHC.Proof: Proving app_law_4 …
GHC.Proof: Proving monad_law_1 …
GHC.Proof: Proving monad_law_2 …
GHC.Proof: Proving monad_law_3 …
GHC.Proof: Proving return_pure …
GHC.Proof proved 15 equalities</code></pre>
<p>This is how I want to prove stuff about my code!</p>
<p>Do you also want to prove stuff about your code? I packaged this up as a GHC plugin in the Haskell library <a href="https://github.com/nomeata/ghc-proofs"><code>ghc-proofs</code></a> (not yet on Hackage). The README of the repository has a bit more detail on how to use this plugin, how it works, what its limitations are and where this is heading.</p>
<p>This is still only a small step, but finally there is a step towards low threshold program equivalence proofs in Haskell.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>Or rather recover my karma after such abominations such as <a href="http://hackage.haskell.org/package/ghc-dup">ghc-dup</a>, <a href="http://hackage.haskell.org/package/seal-module">seal-module</a> or <a href="http://hackage.haskell.org/package/ghc-heap-view">ghc-heap-view</a>.<a href="#fnref1">↩</a></p></li>
</ol>
</div>Mon, 06 Feb 2017 19:38:57 -0500Global almost-constants for Haskell
http://www.joachim-breitner.de/blog/715-Global_almost-constants_for_Haskell
http://www.joachim-breitner.de/blog/715-Global_almost-constants_for_Haskellhttp://www.joachim-breitner.de/blog/715-Global_almost-constants_for_Haskell#commentsmail@joachim-breitner.de (Joachim Breitner)<p>More than five years ago I blogged about the “configuration problem” and a <a href="https://www.joachim-breitner.de/blog/443-A_Solution_to_the_Configuration_Problem_in_Haskell">proposed solution for Haskell</a>, which turned into some Template Haskell hacks in the <a href="http://hackage.haskell.org/package/seal-module">seal-module</a> package.</p>
<p>With the new <a href="https://github.com/ghc-proposals/ghc-proposals/">GHC proposal process</a> in plase, I am suddenly much more inclined to write up my weird wishes for the Haskell language in proposal form, to make them more coherent, get feedback, and maybe (maybe) actually get them implemented. But even if the proposal is rejected it is still a nice forum to discuss these ideas.</p>
<p>So I turned my Template Haskell hack into <a href="https://github.com/ghc-proposals/ghc-proposals/blob/context-fixes/proposals/0000-context-fixes.rst">a proposed new syntactic feature</a>. The idea is shamelessly stolen from Isabelle, including some of the keywords, and would allow you to write</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">context fixes progName <span class="kw">in</span>
<span class="ot"> foo ::</span> <span class="dt">Maybe</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Int</span>
foo <span class="dt">Nothing</span> <span class="fu">=</span> <span class="dt">Left</span> <span class="fu">$</span> progName <span class="fu">++</span> <span class="st">": no number given"</span>
foo (<span class="dt">Just</span> i) <span class="fu">=</span> bar i
<span class="ot"> bar ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Int</span>
bar <span class="dv">0</span> <span class="fu">=</span> <span class="dt">Left</span> <span class="fu">$</span> progName <span class="fu">++</span> <span class="st">": zero no good"</span>
bar n <span class="fu">=</span> <span class="dt">Right</span> <span class="fu">$</span> n <span class="fu">+</span> <span class="dv">1</span></code></pre></div>
<p>instead of</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">foo ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Int</span>
foo progName <span class="dt">Nothing</span> <span class="fu">=</span> <span class="dt">Left</span> <span class="fu">$</span> progName <span class="fu">++</span> <span class="st">": no number given"</span>
foo progName (<span class="dt">Just</span> i) <span class="fu">=</span> bar progName i
<span class="ot">bar ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Int</span>
bar progName <span class="dv">0</span> <span class="fu">=</span> <span class="dt">Left</span> <span class="fu">$</span> progName <span class="fu">++</span> <span class="st">": zero no good"</span>
bar progName n <span class="fu">=</span> <span class="dt">Right</span> <span class="fu">$</span> n <span class="fu">+</span> <span class="dv">1</span></code></pre></div>
<p>when you want to have an “almost constant” parameter.</p>
<p>I am happy to get feedback at the <a href="https://github.com/ghc-proposals/ghc-proposals/pull/40">GitHub pull request</a>.</p>Fri, 20 Jan 2017 13:03:17 -0500Showcasing Applicative
http://www.joachim-breitner.de/blog/710-Showcasing_Applicative
http://www.joachim-breitner.de/blog/710-Showcasing_Applicativehttp://www.joachim-breitner.de/blog/710-Showcasing_Applicative#commentsmail@joachim-breitner.de (Joachim Breitner)<p>My plan for <a href="http://cis.upenn.edu/~cis194/fall16/lectures/09-more-applicative.html">this week’s lecture</a> of the <a href="http://cis.upenn.edu/~cis194/fall16/">CIS 194 Haskell course</a> at the University of Pennsylvania is to dwell a bit on the concept of <code>Functor</code>, <code>Applicative</code> and <code>Monad</code>, and to highlight the value of the <code>Applicative</code> abstraction.</p>
<p>I quite like the example that I came up with, so I want to share it here. In the interest of long-term archival and stand-alone presentation, I include all the material in this post.<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a></p>
<h3 id="imports">Imports</h3>
<p>In case you want to follow along, start with these imports:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">import </span><span class="dt">Data.Char</span>
<span class="kw">import </span><span class="dt">Data.Maybe</span>
<span class="kw">import </span><span class="dt">Data.List</span>
<span class="kw">import </span><span class="dt">System.Environment</span>
<span class="kw">import </span><span class="dt">System.IO</span>
<span class="kw">import </span><span class="dt">System.Exit</span></code></pre></div>
<h3 id="the-parser">The parser</h3>
<p>The starting point for this exercise is a fairly standard parser-combinator monad, which happens to be the result of the student’s homework from last week:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">Parser</span> a <span class="fu">=</span> <span class="dt">P</span> (<span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> (a, <span class="dt">String</span>))
<span class="ot">runParser ::</span> <span class="dt">Parser</span> t <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> (t, <span class="dt">String</span>)
runParser (<span class="dt">P</span> p) <span class="fu">=</span> p
<span class="ot">parse ::</span> <span class="dt">Parser</span> a <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> a
parse p input <span class="fu">=</span> <span class="kw">case</span> runParser p input <span class="kw">of</span>
<span class="dt">Just</span> (result, <span class="st">""</span>) <span class="ot">-></span> <span class="dt">Just</span> result
_ <span class="ot">-></span> <span class="dt">Nothing</span> <span class="co">-- handles both no result and leftover input</span>
<span class="ot">noParserP ::</span> <span class="dt">Parser</span> a
noParserP <span class="fu">=</span> <span class="dt">P</span> (\_ <span class="ot">-></span> <span class="dt">Nothing</span>)
<span class="ot">pureParserP ::</span> a <span class="ot">-></span> <span class="dt">Parser</span> a
pureParserP x <span class="fu">=</span> <span class="dt">P</span> (\input <span class="ot">-></span> <span class="dt">Just</span> (x,input))
<span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Parser</span> <span class="kw">where</span>
fmap f p <span class="fu">=</span> <span class="dt">P</span> <span class="fu">$</span> \input <span class="ot">-></span> <span class="kw">do</span>
(x, rest) <span class="ot"><-</span> runParser p input
return (f x, rest)
<span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Parser</span> <span class="kw">where</span>
pure <span class="fu">=</span> pureParserP
p1 <span class="fu"><*></span> p2 <span class="fu">=</span> <span class="dt">P</span> <span class="fu">$</span> \input <span class="ot">-></span> <span class="kw">do</span>
(f, rest1) <span class="ot"><-</span> runParser p1 input
(x, rest2) <span class="ot"><-</span> runParser p2 rest1
return (f x, rest2)
<span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Parser</span> <span class="kw">where</span>
return <span class="fu">=</span> pure
p1 <span class="fu">>>=</span> k <span class="fu">=</span> <span class="dt">P</span> <span class="fu">$</span> \input <span class="ot">-></span> <span class="kw">do</span>
(x, rest1) <span class="ot"><-</span> runParser p1 input
runParser (k x) rest1
<span class="ot">anyCharP ::</span> <span class="dt">Parser</span> <span class="dt">Char</span>
anyCharP <span class="fu">=</span> <span class="dt">P</span> <span class="fu">$</span> \input <span class="ot">-></span> <span class="kw">case</span> input <span class="kw">of</span>
(c<span class="fu">:</span>rest) <span class="ot">-></span> <span class="dt">Just</span> (c, rest)
[] <span class="ot">-></span> <span class="dt">Nothing</span>
<span class="ot">charP ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">Parser</span> ()
charP c <span class="fu">=</span> <span class="kw">do</span>
c' <span class="ot"><-</span> anyCharP
<span class="kw">if</span> c <span class="fu">==</span> c' <span class="kw">then</span> return ()
<span class="kw">else</span> noParserP
<span class="ot">anyCharButP ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">Parser</span> <span class="dt">Char</span>
anyCharButP c <span class="fu">=</span> <span class="kw">do</span>
c' <span class="ot"><-</span> anyCharP
<span class="kw">if</span> c <span class="fu">/=</span> c' <span class="kw">then</span> return c'
<span class="kw">else</span> noParserP
<span class="ot">letterOrDigitP ::</span> <span class="dt">Parser</span> <span class="dt">Char</span>
letterOrDigitP <span class="fu">=</span> <span class="kw">do</span>
c <span class="ot"><-</span> anyCharP
<span class="kw">if</span> isAlphaNum c <span class="kw">then</span> return c <span class="kw">else</span> noParserP
<span class="ot">orElseP ::</span> <span class="dt">Parser</span> a <span class="ot">-></span> <span class="dt">Parser</span> a <span class="ot">-></span> <span class="dt">Parser</span> a
orElseP p1 p2 <span class="fu">=</span> <span class="dt">P</span> <span class="fu">$</span> \input <span class="ot">-></span> <span class="kw">case</span> runParser p1 input <span class="kw">of</span>
<span class="dt">Just</span> r <span class="ot">-></span> <span class="dt">Just</span> r
<span class="dt">Nothing</span> <span class="ot">-></span> runParser p2 input
<span class="ot">manyP ::</span> <span class="dt">Parser</span> a <span class="ot">-></span> <span class="dt">Parser</span> [a]
manyP p <span class="fu">=</span> (pure (<span class="fu">:</span>) <span class="fu"><*></span> p <span class="fu"><*></span> manyP p) <span class="ot">`orElseP`</span> pure []
<span class="ot">many1P ::</span> <span class="dt">Parser</span> a <span class="ot">-></span> <span class="dt">Parser</span> [a]
many1P p <span class="fu">=</span> pure (<span class="fu">:</span>) <span class="fu"><*></span> p <span class="fu"><*></span> manyP p
<span class="ot">sepByP ::</span> <span class="dt">Parser</span> a <span class="ot">-></span> <span class="dt">Parser</span> () <span class="ot">-></span> <span class="dt">Parser</span> [a]
sepByP p1 p2 <span class="fu">=</span> (pure (<span class="fu">:</span>) <span class="fu"><*></span> p1 <span class="fu"><*></span> (manyP (p2 <span class="fu">*></span> p1))) <span class="ot">`orElseP`</span> pure []</code></pre></div>
<p>A parser using this library for, for example, CSV files could take this form:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseCSVP ::</span> <span class="dt">Parser</span> [[<span class="dt">String</span>]]
parseCSVP <span class="fu">=</span> manyP parseLine
<span class="kw">where</span>
parseLine <span class="fu">=</span> parseCell <span class="ot">`sepByP`</span> charP <span class="ch">','</span> <span class="fu"><*</span> charP <span class="ch">'\n'</span>
parseCell <span class="fu">=</span> <span class="kw">do</span>
charP <span class="ch">'"'</span>
content <span class="ot"><-</span> manyP (anyCharButP <span class="ch">'"'</span>)
charP <span class="ch">'"'</span>
return content</code></pre></div>
<h3 id="we-want-ebnf">We want EBNF</h3>
<p>Often when we write a parser for a file format, we might also want to have a formal specification of the format. A common form for such a specification is <a href="https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form">EBNF</a>. This might look as follows, for a CSV file:</p>
<pre><code>cell = '"', {not-quote}, '"';
line = (cell, {',', cell} | ''), newline;
csv = {line};</code></pre>
<p>It is straightforward to create a Haskell data type to represent an EBNF syntax description. Here is a simple EBNF library (data type and pretty-printer) for your convenience:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">RHS</span>
<span class="fu">=</span> <span class="dt">Terminal</span> <span class="dt">String</span>
<span class="fu">|</span> <span class="dt">NonTerminal</span> <span class="dt">String</span>
<span class="fu">|</span> <span class="dt">Choice</span> <span class="dt">RHS</span> <span class="dt">RHS</span>
<span class="fu">|</span> <span class="dt">Sequence</span> <span class="dt">RHS</span> <span class="dt">RHS</span>
<span class="fu">|</span> <span class="dt">Optional</span> <span class="dt">RHS</span>
<span class="fu">|</span> <span class="dt">Repetition</span> <span class="dt">RHS</span>
<span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)
<span class="ot">ppRHS ::</span> <span class="dt">RHS</span> <span class="ot">-></span> <span class="dt">String</span>
ppRHS <span class="fu">=</span> go <span class="dv">0</span>
<span class="kw">where</span>
go _ (<span class="dt">Terminal</span> s) <span class="fu">=</span> surround <span class="st">"'"</span> <span class="st">"'"</span> <span class="fu">$</span> concatMap quote s
go _ (<span class="dt">NonTerminal</span> s) <span class="fu">=</span> s
go a (<span class="dt">Choice</span> x1 x2) <span class="fu">=</span> p a <span class="dv">1</span> <span class="fu">$</span> go <span class="dv">1</span> x1 <span class="fu">++</span> <span class="st">" | "</span> <span class="fu">++</span> go <span class="dv">1</span> x2
go a (<span class="dt">Sequence</span> x1 x2) <span class="fu">=</span> p a <span class="dv">2</span> <span class="fu">$</span> go <span class="dv">2</span> x1 <span class="fu">++</span> <span class="st">", "</span> <span class="fu">++</span> go <span class="dv">2</span> x2
go _ (<span class="dt">Optional</span> x) <span class="fu">=</span> surround <span class="st">"["</span> <span class="st">"]"</span> <span class="fu">$</span> go <span class="dv">0</span> x
go _ (<span class="dt">Repetition</span> x) <span class="fu">=</span> surround <span class="st">"{"</span> <span class="st">"}"</span> <span class="fu">$</span> go <span class="dv">0</span> x
surround c1 c2 x <span class="fu">=</span> c1 <span class="fu">++</span> x <span class="fu">++</span> c2
p a n <span class="fu">|</span> a <span class="fu">></span> n <span class="fu">=</span> surround <span class="st">"("</span> <span class="st">")"</span>
<span class="fu">|</span> otherwise <span class="fu">=</span> id
quote <span class="ch">'\''</span> <span class="fu">=</span> <span class="st">"\\'"</span>
quote <span class="ch">'\\'</span> <span class="fu">=</span> <span class="st">"\\\\"</span>
quote c <span class="fu">=</span> [c]
<span class="kw">type</span> <span class="dt">Production</span> <span class="fu">=</span> (<span class="dt">String</span>, <span class="dt">RHS</span>)
<span class="kw">type</span> <span class="dt">BNF</span> <span class="fu">=</span> [<span class="dt">Production</span>]
<span class="ot">ppBNF ::</span> <span class="dt">BNF</span> <span class="ot">-></span> <span class="dt">String</span>
ppBNF <span class="fu">=</span> unlines <span class="fu">.</span> map (\(i,rhs) <span class="ot">-></span> i <span class="fu">++</span> <span class="st">" = "</span> <span class="fu">++</span> ppRHS rhs <span class="fu">++</span> <span class="st">";"</span>)</code></pre></div>
<h3 id="code-to-produce-ebnf">Code to produce EBNF</h3>
<p>We had a good time writing combinators that create complex parsers from primitive pieces. Let us do the same for EBNF grammars. We could simply work on the <code>RHS</code> type directly, but we can do something more nifty: We create a data type that keeps track, via a <em>phantom</em> type parameter, of what Haskell type the given EBNF syntax is the specification:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">Grammar</span> a <span class="fu">=</span> <span class="dt">G</span> <span class="dt">RHS</span>
<span class="ot">ppGrammar ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">String</span>
ppGrammar (<span class="dt">G</span> rhs) <span class="fu">=</span> ppRHS rhs</code></pre></div>
<p>So a value of type <code>Grammar t</code> is a description of the textual representation of the Haskell type <code>t</code>.</p>
<p>Here is one simple example:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">anyCharG ::</span> <span class="dt">Grammar</span> <span class="dt">Char</span>
anyCharG <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">NonTerminal</span> <span class="st">"char"</span>)</code></pre></div>
<p>Here is another one. This one does not describe any interesting Haskell type, but is useful when spelling out the special characters in the syntax described by the grammar:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">charG ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">Grammar</span> ()
charG c <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Terminal</span> [c])</code></pre></div>
<p>A combinator that creates new grammar from two existing grammars:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">orElseG ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> a
orElseG (<span class="dt">G</span> rhs1) (<span class="dt">G</span> rhs2) <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Choice</span> rhs1 rhs2)</code></pre></div>
<p>We want the convenience of our well-known type classes in order to combine these values some more:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Grammar</span> <span class="kw">where</span>
fmap _ (<span class="dt">G</span> rhs) <span class="fu">=</span> <span class="dt">G</span> rhs
<span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Grammar</span> <span class="kw">where</span>
pure x <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Terminal</span> <span class="st">""</span>)
(<span class="dt">G</span> rhs1) <span class="fu"><*></span> (<span class="dt">G</span> rhs2) <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Sequence</span> rhs1 rhs2)</code></pre></div>
<p>Note how the <code>Functor</code> instance does not actually use the function. How should it? There are no values inside a <code>Grammar</code>!</p>
<p>We cannot define a <code>Monad</code> instance for <code>Grammar</code>: We would start with <code>(G rhs1) >>= k = …</code>, but there is simply no way of getting a value of type <code>a</code> that we can feed to <code>k</code>. So we will do without a <code>Monad</code> instance. This is interesting, and we will come back to that later.</p>
<p>Like with the parser, we can now begin to build on the primitive example to build more complicated combinators:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">manyG ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> [a]
manyG p <span class="fu">=</span> (pure (<span class="fu">:</span>) <span class="fu"><*></span> p <span class="fu"><*></span> manyG p) <span class="ot">`orElseG`</span> pure []
<span class="ot">many1G ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> [a]
many1G p <span class="fu">=</span> pure (<span class="fu">:</span>) <span class="fu"><*></span> p <span class="fu"><*></span> manyG p
<span class="ot">sepByG ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> () <span class="ot">-></span> <span class="dt">Grammar</span> [a]
sepByG p1 p2 <span class="fu">=</span> ((<span class="fu">:</span>) <span class="fu"><$></span> p1 <span class="fu"><*></span> (manyG (p2 <span class="fu">*></span> p1))) <span class="ot">`orElseG`</span> pure []</code></pre></div>
<p>Let us run a small example:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">dottedWordsG ::</span> <span class="dt">Grammar</span> [<span class="dt">String</span>]
dottedWordsG <span class="fu">=</span> many1G (manyG anyCharG <span class="fu"><*</span> charG <span class="ch">'.'</span>)</code></pre></div>
<pre><code>*Main> putStrLn $ ppGrammar dottedWordsG
'', ('', char, ('', char, ('', char, ('', char, ('', char, ('', …</code></pre>
<p>Oh my, that is not good. Looks like the recursion in <code>manyG</code> does not work well, so we need to avoid that. But anyways we want to be explicit in the EBNF grammars about where something can be repeated, so let us just make <code>many</code> a primitive:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">manyG ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> [a]
manyG (<span class="dt">G</span> rhs) <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Repetition</span> rhs)</code></pre></div>
<p>With this definition, we already get a simple grammar for <code>dottedWordsG</code>:</p>
<pre><code>*Main> putStrLn $ ppGrammar dottedWordsG
'', {char}, '.', {{char}, '.'}</code></pre>
<p>This already looks like a proper EBNF grammar. One thing that is not nice about it is that there is an empty string (<code>''</code>) in a sequence (<code>…,…</code>). We do not want that.</p>
<p>Why is it there in the first place? Because our <code>Applicative</code> instance is not lawful! Remember that <code>pure id <*> g == g</code> should hold. One way to achieve that is to improve the <code>Applicative</code> instance to optimize this case away:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Grammar</span> <span class="kw">where</span>
pure x <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Terminal</span> <span class="st">""</span>)
<span class="dt">G</span> (<span class="dt">Terminal</span> <span class="st">""</span>) <span class="fu"><*></span> <span class="dt">G</span> rhs2 <span class="fu">=</span> <span class="dt">G</span> rhs2
<span class="dt">G</span> rhs1 <span class="fu"><*></span> <span class="dt">G</span> (<span class="dt">Terminal</span> <span class="st">""</span>) <span class="fu">=</span> <span class="dt">G</span> rhs1
(<span class="dt">G</span> rhs1) <span class="fu"><*></span> (<span class="dt">G</span> rhs2) <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">Sequence</span> rhs1 rhs2)
<span class="ot">```</span>
<span class="ot">Now we get what we want:</span></code></pre></div>
<pre><code>*Main> putStrLn $ ppGrammar dottedWordsG
{char}, '.', {{char}, '.'}</code></pre>
<p>Remember our parser for CSV files above? Let me repeat it here, this time using only <code>Applicative</code> combinators, i.e. avoiding <code>(>>=)</code>, <code>(>>)</code>, <code>return</code> and <code>do</code>-notation:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseCSVP ::</span> <span class="dt">Parser</span> [[<span class="dt">String</span>]]
parseCSVP <span class="fu">=</span> manyP parseLine
<span class="kw">where</span>
parseLine <span class="fu">=</span> parseCell <span class="ot">`sepByP`</span> charG <span class="ch">','</span> <span class="fu"><*</span> charP <span class="ch">'\n'</span>
parseCell <span class="fu">=</span> charP <span class="ch">'"'</span> <span class="fu">*></span> manyP (anyCharButP <span class="ch">'"'</span>) <span class="fu"><*</span> charP <span class="ch">'"'</span></code></pre></div>
<p>And now we try to rewrite the code to produce <code>Grammar</code> instead of <code>Parser</code>. This is straightforward with the exception of <code>anyCharButP</code>. The parser code for that inherently monadic, and we just do not have a monad instance. So we work around the issue by making that a “primitive” grammar, i.e. introducing a non-terminal in the EBNF without a production rule – pretty much like we did for <code>anyCharG</code>:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">primitiveG ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Grammar</span> a
primitiveG s <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">NonTerminal</span> s)
<span class="ot">parseCSVG ::</span> <span class="dt">Grammar</span> [[<span class="dt">String</span>]]
parseCSVG <span class="fu">=</span> manyG parseLine
<span class="kw">where</span>
parseLine <span class="fu">=</span> parseCell <span class="ot">`sepByG`</span> charG <span class="ch">','</span> <span class="fu"><*</span> charG <span class="ch">'\n'</span>
parseCell <span class="fu">=</span> charG <span class="ch">'"'</span> <span class="fu">*></span> manyG (primitiveG <span class="st">"not-quote"</span>) <span class="fu"><*</span> charG <span class="ch">'"'</span></code></pre></div>
<p>Of course the names <code>parse…</code> are not quite right any more, but let us just leave that for now.</p>
<p>Here is the result:</p>
<pre><code>*Main> putStrLn $ ppGrammar parseCSVG
{('"', {not-quote}, '"', {',', '"', {not-quote}, '"'} | ''), '
'}</code></pre>
<p>The line break is weird. We do not really want newlines in the grammar. So let us make that primitive as well, and replace <code>charG '\n'</code> with <code>newlineG</code>:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">newlineG ::</span> <span class="dt">Grammar</span> ()
newlineG <span class="fu">=</span> primitiveG <span class="st">"newline"</span></code></pre></div>
<p>Now we get</p>
<pre><code>*Main> putStrLn $ ppGrammar parseCSVG
{('"', {not-quote}, '"', {',', '"', {not-quote}, '"'} | ''), newline}</code></pre>
<p>which is nice and correct, but still not quite the easily readable EBNF that we saw further up.</p>
<h3 id="code-to-produce-ebnf-with-productions">Code to produce EBNF, with productions</h3>
<p>We currently let our grammars produce only the right-hand side of one EBNF production, but really, we want to produce a RHS that may refer to other productions. So let us change the type accordingly:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">Grammar</span> a <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">BNF</span>, <span class="dt">RHS</span>)
<span class="ot">runGrammer ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">BNF</span>
runGrammer main (<span class="dt">G</span> (prods, rhs)) <span class="fu">=</span> prods <span class="fu">++</span> [(main, rhs)]
<span class="ot">ppGrammar ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">String</span>
ppGrammar main g <span class="fu">=</span> ppBNF <span class="fu">$</span> runGrammer main g</code></pre></div>
<p>Now we have to adjust all our primitive combinators (but not the derived ones!):</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">charG ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">Grammar</span> ()
charG c <span class="fu">=</span> <span class="dt">G</span> ([], <span class="dt">Terminal</span> [c])
<span class="ot">anyCharG ::</span> <span class="dt">Grammar</span> <span class="dt">Char</span>
anyCharG <span class="fu">=</span> <span class="dt">G</span> ([], <span class="dt">NonTerminal</span> <span class="st">"char"</span>)
<span class="ot">manyG ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> [a]
manyG (<span class="dt">G</span> (prods, rhs)) <span class="fu">=</span> <span class="dt">G</span> (prods, <span class="dt">Repetition</span> rhs)
<span class="ot">mergeProds ::</span> [<span class="dt">Production</span>] <span class="ot">-></span> [<span class="dt">Production</span>] <span class="ot">-></span> [<span class="dt">Production</span>]
mergeProds prods1 prods2 <span class="fu">=</span> nub <span class="fu">$</span> prods1 <span class="fu">++</span> prods2
<span class="ot">orElseG ::</span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> a
orElseG (<span class="dt">G</span> (prods1, rhs1)) (<span class="dt">G</span> (prods2, rhs2))
<span class="fu">=</span> <span class="dt">G</span> (mergeProds prods1 prods2, <span class="dt">Choice</span> rhs1 rhs2)
<span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Grammar</span> <span class="kw">where</span>
fmap _ (<span class="dt">G</span> bnf) <span class="fu">=</span> <span class="dt">G</span> bnf
<span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Grammar</span> <span class="kw">where</span>
pure x <span class="fu">=</span> <span class="dt">G</span> ([], <span class="dt">Terminal</span> <span class="st">""</span>)
<span class="dt">G</span> (prods1, <span class="dt">Terminal</span> <span class="st">""</span>) <span class="fu"><*></span> <span class="dt">G</span> (prods2, rhs2)
<span class="fu">=</span> <span class="dt">G</span> (mergeProds prods1 prods2, rhs2)
<span class="dt">G</span> (prods1, rhs1) <span class="fu"><*></span> <span class="dt">G</span> (prods2, <span class="dt">Terminal</span> <span class="st">""</span>)
<span class="fu">=</span> <span class="dt">G</span> (mergeProds prods1 prods2, rhs1)
<span class="dt">G</span> (prods1, rhs1) <span class="fu"><*></span> <span class="dt">G</span> (prods2, rhs2)
<span class="fu">=</span> <span class="dt">G</span> (mergeProds prods1 prods2, <span class="dt">Sequence</span> rhs1 rhs2)
<span class="ot">primitiveG ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Grammar</span> a
primitiveG s <span class="fu">=</span> <span class="dt">G</span> (<span class="dt">NonTerminal</span> s)</code></pre></div>
<p>The use of <code>nub</code> when combining productions removes duplicates that might be used in different parts of the grammar. Not efficient, but good enough for now.</p>
<p>Did we gain anything? Not yet:</p>
<pre><code>*Main> putStr $ ppGrammar "csv" (parseCSVG)
csv = {('"', {not-quote}, '"', {',', '"', {not-quote}, '"'} | ''), newline};</code></pre>
<p>But we can now introduce a function that lets us tell the system where to give names to a piece of grammar:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">nonTerminal ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> a
nonTerminal name (<span class="dt">G</span> (prods, rhs))
<span class="fu">=</span> <span class="dt">G</span> (prods <span class="fu">++</span> [(name, rhs)], <span class="dt">NonTerminal</span> name)</code></pre></div>
<p>Ample use of this in <code>parseCSVG</code> yields the desired result:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseCSVG ::</span> <span class="dt">Grammar</span> [[<span class="dt">String</span>]]
parseCSVG <span class="fu">=</span> manyG parseLine
<span class="kw">where</span>
parseLine <span class="fu">=</span> nonTerminal <span class="st">"line"</span> <span class="fu">$</span>
parseCell <span class="ot">`sepByG`</span> charG <span class="ch">','</span> <span class="fu"><*</span> newline
parseCell <span class="fu">=</span> nonTerminal <span class="st">"cell"</span> <span class="fu">$</span>
charG <span class="ch">'"'</span> <span class="fu">*></span> manyG (primitiveG <span class="st">"not-quote"</span>) <span class="fu"><*</span> charG <span class="ch">'"</span></code></pre></div>
<pre><code>*Main> putStr $ ppGrammar "csv" (parseCSVG)
cell = '"', {not-quote}, '"';
line = (cell, {',', cell} | ''), newline;
csv = {line};</code></pre>
<p>This is great!</p>
<h3 id="unifying-parsing-and-grammar-generating">Unifying parsing and grammar-generating</h3>
<p>Note how simliar <code>parseCSVG</code> and <code>parseCSVP</code> are! Would it not be great if we could implement that functionality only once, and get both a parser <em>and</em> a grammar description out of it? This way, the two would never be out of sync!</p>
<p>And surely this must be possible. The tool to reach for is of course to define a type class that abstracts over the parts where <code>Parser</code> and <code>Grammer</code> differ. So we have to identify all functions that are primitive in one of the two worlds, and turn them into type class methods. This includes <code>char</code> and <code>orElse</code>. It includes <code>many</code>, too: Although <code>manyP</code> is not primitive, <code>manyG</code> is. It also includes <code>nonTerminal</code>, which does not exist in the world of parsers (yet), but we need it for the grammars.</p>
<p>The <code>primitiveG</code> function is tricky. We use it in grammars when the code that we might use while parsing is not expressible as a grammar. So the solution is to let it take two arguments: A <code>String</code>, when used as a descriptive non-terminal in a grammar, and a <code>Parser a</code>, used in the parsing code.</p>
<p>Finally, the type classes that we except, <code>Applicative</code> (and thus <code>Functor</code>), are added as constraints on our type class:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">class</span> <span class="dt">Applicative</span> f <span class="ot">=></span> <span class="dt">Descr</span> f <span class="kw">where</span>
<span class="ot"> char ::</span> <span class="dt">Char</span> <span class="ot">-></span> f ()
<span class="ot"> many ::</span> f a <span class="ot">-></span> f [a]
<span class="ot"> orElse ::</span> f a <span class="ot">-></span> f a <span class="ot">-></span> f a
<span class="ot"> primitive ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Parser</span> a <span class="ot">-></span> f a
<span class="ot"> nonTerminal ::</span> <span class="dt">String</span> <span class="ot">-></span> f a <span class="ot">-></span> f a</code></pre></div>
<p>The instances are easily written:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">instance</span> <span class="dt">Descr</span> <span class="dt">Parser</span> <span class="kw">where</span>
char <span class="fu">=</span> charP
many <span class="fu">=</span> manyP
orElse <span class="fu">=</span> orElseP
<span class="kw">primitive</span> _ p <span class="fu">=</span> p
nonTerminal _ p <span class="fu">=</span> p
<span class="kw">instance</span> <span class="dt">Descr</span> <span class="dt">Grammar</span> <span class="kw">where</span>
char <span class="fu">=</span> charG
many <span class="fu">=</span> manyG
orElse <span class="fu">=</span> orElseG
<span class="kw">primitive</span> s _ <span class="fu">=</span> primitiveG s
nonTerminal s g <span class="fu">=</span> nonTerminal s g</code></pre></div>
<p>And we can now take the derived definitions, of which so far we had two copies, and define them once and for all:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">many1 ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f a <span class="ot">-></span> f [a]
many1 p <span class="fu">=</span> pure (<span class="fu">:</span>) <span class="fu"><*></span> p <span class="fu"><*></span> many p
<span class="ot">anyChar ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Char</span>
anyChar <span class="fu">=</span> <span class="kw">primitive</span> <span class="st">"char"</span> anyCharP
<span class="ot">dottedWords ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f [<span class="dt">String</span>]
dottedWords <span class="fu">=</span> many1 (many anyChar <span class="fu"><*</span> char <span class="ch">'.'</span>)
<span class="ot">sepBy ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f a <span class="ot">-></span> f () <span class="ot">-></span> f [a]
sepBy p1 p2 <span class="fu">=</span> ((<span class="fu">:</span>) <span class="fu"><$></span> p1 <span class="fu"><*></span> (many (p2 <span class="fu">*></span> p1))) <span class="ot">`orElse`</span> pure []
<span class="ot">newline ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f ()
newline <span class="fu">=</span> <span class="kw">primitive</span> <span class="st">"newline"</span> (charP <span class="ch">'\n'</span>)</code></pre></div>
<p>And thus we now have our CSV parser/grammar generator:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseCSV ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f [[<span class="dt">String</span>]]
parseCSV <span class="fu">=</span> many parseLine
<span class="kw">where</span>
parseLine <span class="fu">=</span> nonTerminal <span class="st">"line"</span> <span class="fu">$</span>
parseCell <span class="ot">`sepBy`</span> char <span class="ch">','</span> <span class="fu"><*</span> newline
parseCell <span class="fu">=</span> nonTerminal <span class="st">"cell"</span> <span class="fu">$</span>
char <span class="ch">'"'</span> <span class="fu">*></span> many (<span class="kw">primitive</span> <span class="st">"not-quote"</span> (anyCharButP <span class="ch">'"'</span>)) <span class="fu"><*</span> char <span class="ch">'"'</span></code></pre></div>
<p>We can now use this definition both to parse and to generate grammars:</p>
<pre><code>*Main> putStr $ ppGrammar2 "csv" (parseCSV)
cell = '"', {not-quote}, '"';
line = (cell, {',', cell} | ''), newline;
csv = {line};
*Main> parse parseCSV "\"ab\",\"cd\"\n\"\",\"de\"\n\n"
Just [["ab","cd"],["","de"],[]]</code></pre>
<h3 id="the-ini-file-parser-and-grammar">The INI file parser and grammar</h3>
<p>As a final exercise, let us transform the INI file parser into a combined thing. Here is the parser (another artifact of last week’s homework) again using applicative style<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a>:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseINIP ::</span> <span class="dt">Parser</span> <span class="dt">INIFile</span>
parseINIP <span class="fu">=</span> many1P parseSection
<span class="kw">where</span>
parseSection <span class="fu">=</span>
(,) <span class="fu"><$</span> charP <span class="ch">'['</span>
<span class="fu"><*></span> parseIdent
<span class="fu"><*</span> charP <span class="ch">']'</span>
<span class="fu"><*</span> charP <span class="ch">'\n'</span>
<span class="fu"><*></span> (catMaybes <span class="fu"><$></span> manyP parseLine)
parseIdent <span class="fu">=</span> many1P letterOrDigitP
parseLine <span class="fu">=</span> parseDecl <span class="ot">`orElseP`</span> parseComment <span class="ot">`orElseP`</span> parseEmpty
parseDecl <span class="fu">=</span> <span class="dt">Just</span> <span class="fu"><$></span> (
(,) <span class="fu"><*></span> parseIdent
<span class="fu"><*</span> manyP (charP <span class="ch">' '</span>)
<span class="fu"><*</span> charP <span class="ch">'='</span>
<span class="fu"><*</span> manyP (charP <span class="ch">' '</span>)
<span class="fu"><*></span> many1P (anyCharButP <span class="ch">'\n'</span>)
<span class="fu"><*</span> charP <span class="ch">'\n'</span>)
parseComment <span class="fu">=</span>
<span class="dt">Nothing</span> <span class="fu"><$</span> charP <span class="ch">'#'</span>
<span class="fu"><*</span> many1P (anyCharButP <span class="ch">'\n'</span>)
<span class="fu"><*</span> charP <span class="ch">'\n'</span>
parseEmpty <span class="fu">=</span> <span class="dt">Nothing</span> <span class="fu"><$</span> charP <span class="ch">'\n'</span></code></pre></div>
<p>Transforming that to a generic description is quite straightforward. We use <code>primitive</code> again to wrap <code>letterOrDigitP</code>:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">descrINI ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">INIFile</span>
descrINI <span class="fu">=</span> many1 parseSection
<span class="kw">where</span>
parseSection <span class="fu">=</span>
(,) <span class="fu"><*</span> char <span class="ch">'['</span>
<span class="fu"><*></span> parseIdent
<span class="fu"><*</span> char <span class="ch">']'</span>
<span class="fu"><*</span> newline
<span class="fu"><*></span> (catMaybes <span class="fu"><$></span> many parseLine)
parseIdent <span class="fu">=</span> many1 (<span class="kw">primitive</span> <span class="st">"alphanum"</span> letterOrDigitP)
parseLine <span class="fu">=</span> parseDecl <span class="ot">`orElse`</span> parseComment <span class="ot">`orElse`</span> parseEmpty
parseDecl <span class="fu">=</span> <span class="dt">Just</span> <span class="fu"><$></span> (
(,) <span class="fu"><*></span> parseIdent
<span class="fu"><*</span> many (char <span class="ch">' '</span>)
<span class="fu"><*</span> char <span class="ch">'='</span>
<span class="fu"><*</span> many (char <span class="ch">' '</span>)
<span class="fu"><*></span> many1 (<span class="kw">primitive</span> <span class="st">"non-newline"</span> (anyCharButP <span class="ch">'\n'</span>))
<span class="fu"><*</span> newline)
parseComment <span class="fu">=</span>
<span class="dt">Nothing</span> <span class="fu"><$</span> char <span class="ch">'#'</span>
<span class="fu"><*</span> many1 (<span class="kw">primitive</span> <span class="st">"non-newline"</span> (anyCharButP <span class="ch">'\n'</span>))
<span class="fu"><*</span> newline
parseEmpty <span class="fu">=</span> <span class="dt">Nothing</span> <span class="fu"><$</span> newline</code></pre></div>
<p>This yields this not very helpful grammar (abbreviated here):</p>
<pre><code>*Main> putStr $ ppGrammar2 "ini" descrINI
ini = '[', alphanum, {alphanum}, ']', newline, {alphanum, {alphanum}, {' '}…</code></pre>
<p>But with a few uses of <code>nonTerminal</code>, we get something really nice:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">descrINI ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">INIFile</span>
descrINI <span class="fu">=</span> many1 parseSection
<span class="kw">where</span>
parseSection <span class="fu">=</span> nonTerminal <span class="st">"section"</span> <span class="fu">$</span>
(,) <span class="fu"><$</span> char <span class="ch">'['</span>
<span class="fu"><*></span> parseIdent
<span class="fu"><*</span> char <span class="ch">']'</span>
<span class="fu"><*</span> newline
<span class="fu"><*></span> (catMaybes <span class="fu"><$></span> many parseLine)
parseIdent <span class="fu">=</span> nonTerminal <span class="st">"identifier"</span> <span class="fu">$</span>
many1 (<span class="kw">primitive</span> <span class="st">"alphanum"</span> letterOrDigitP)
parseLine <span class="fu">=</span> nonTerminal <span class="st">"line"</span> <span class="fu">$</span>
parseDecl <span class="ot">`orElse`</span> parseComment <span class="ot">`orElse`</span> parseEmpty
parseDecl <span class="fu">=</span> nonTerminal <span class="st">"declaration"</span> <span class="fu">$</span> <span class="dt">Just</span> <span class="fu"><$></span> (
(,) <span class="fu"><$></span> parseIdent
<span class="fu"><*</span> spaces
<span class="fu"><*</span> char <span class="ch">'='</span>
<span class="fu"><*</span> spaces
<span class="fu"><*></span> remainder)
parseComment <span class="fu">=</span> nonTerminal <span class="st">"comment"</span> <span class="fu">$</span>
<span class="dt">Nothing</span> <span class="fu"><$</span> char <span class="ch">'#'</span> <span class="fu"><*</span> remainder
remainder <span class="fu">=</span> nonTerminal <span class="st">"line-remainder"</span> <span class="fu">$</span>
many1 (<span class="kw">primitive</span> <span class="st">"non-newline"</span> (anyCharButP <span class="ch">'\n'</span>)) <span class="fu"><*</span> newline
parseEmpty <span class="fu">=</span> <span class="dt">Nothing</span> <span class="fu"><$</span> newline
spaces <span class="fu">=</span> nonTerminal <span class="st">"spaces"</span> <span class="fu">$</span> many (char <span class="ch">' '</span>)</code></pre></div>
<pre><code>*Main> putStr $ ppGrammar "ini" descrINI
identifier = alphanum, {alphanum};
spaces = {' '};
line-remainder = non-newline, {non-newline}, newline;
declaration = identifier, spaces, '=', spaces, line-remainder;
comment = '#', line-remainder;
line = declaration | comment | newline;
section = '[', identifier, ']', newline, {line};
ini = section, {section};</code></pre>
<h3 id="recursion-variant-1">Recursion (variant 1)</h3>
<p>What if we want to write a parser/grammar-generator that is able to generate the following grammar, which describes terms that are additions and multiplications of natural numbers:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell">const <span class="fu">=</span> digit, {digit};
spaces <span class="fu">=</span> {<span class="ch">' '</span> <span class="fu">|</span> newline};
atom <span class="fu">=</span> const <span class="fu">|</span> <span class="ch">'('</span>, spaces, expr, spaces, <span class="ch">')'</span>, spaces;
mult <span class="fu">=</span> atom, {spaces, <span class="ch">'*'</span>, spaces, atom}, spaces;
plus <span class="fu">=</span> mult, {spaces, <span class="ch">'+'</span>, spaces, mult}, spaces;
expr <span class="fu">=</span> plus;</code></pre></div>
<p>The production of <code>expr</code> is recursive (via <code>plus</code>, <code>mult</code>, <code>atom</code>). We have seen above that simply defining a <code>Grammar a</code> recursively does not go well.</p>
<p>One solution is to add a new combinator for explicit recursion, which replaces <code>nonTerminal</code> in the method:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">class</span> <span class="dt">Applicative</span> f <span class="ot">=></span> <span class="dt">Descr</span> f <span class="kw">where</span>
…
<span class="ot"> recNonTerminal ::</span> <span class="dt">String</span> <span class="ot">-></span> (f a <span class="ot">-></span> f a) <span class="ot">-></span> f a
<span class="kw">instance</span> <span class="dt">Descr</span> <span class="dt">Parser</span> <span class="kw">where</span>
…
recNonTerminal _ p <span class="fu">=</span> <span class="kw">let</span> r <span class="fu">=</span> p r <span class="kw">in</span> r
<span class="kw">instance</span> <span class="dt">Descr</span> <span class="dt">Grammar</span> <span class="kw">where</span>
…
recNonTerminal <span class="fu">=</span> recNonTerminalG
<span class="ot">recNonTerminalG ::</span> <span class="dt">String</span> <span class="ot">-></span> (<span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">Grammar</span> a) <span class="ot">-></span> <span class="dt">Grammar</span> a
recNonTerminalG name f <span class="fu">=</span>
<span class="kw">let</span> <span class="dt">G</span> (prods, rhs) <span class="fu">=</span> f (<span class="dt">G</span> ([], <span class="dt">NonTerminal</span> name))
<span class="kw">in</span> <span class="dt">G</span> (prods <span class="fu">++</span> [(name, rhs)], <span class="dt">NonTerminal</span> name)
<span class="ot">nonTerminal ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> <span class="dt">String</span> <span class="ot">-></span> f a <span class="ot">-></span> f a
nonTerminal name p <span class="fu">=</span> recNonTerminal name (const p)
<span class="ot">runGrammer ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Grammar</span> a <span class="ot">-></span> <span class="dt">BNF</span>
runGrammer main (<span class="dt">G</span> (prods, <span class="dt">NonTerminal</span> nt)) <span class="fu">|</span> main <span class="fu">==</span> nt <span class="fu">=</span> prods
runGrammer main (<span class="dt">G</span> (prods, rhs)) <span class="fu">=</span> prods <span class="fu">++</span> [(main, rhs)]</code></pre></div>
<p>The change in <code>runGrammer</code> avoids adding a pointless <code>expr = expr</code> production to the output.</p>
<p>This lets us define a parser/grammar-generator for the arithmetic expressions given above:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Expr</span> <span class="fu">=</span> <span class="dt">Plus</span> <span class="dt">Expr</span> <span class="dt">Expr</span> <span class="fu">|</span> <span class="dt">Mult</span> <span class="dt">Expr</span> <span class="dt">Expr</span> <span class="fu">|</span> <span class="dt">Const</span> <span class="dt">Integer</span>
<span class="kw">deriving</span> <span class="dt">Show</span>
<span class="ot">mkPlus ::</span> <span class="dt">Expr</span> <span class="ot">-></span> [<span class="dt">Expr</span>] <span class="ot">-></span> <span class="dt">Expr</span>
mkPlus <span class="fu">=</span> foldl <span class="dt">Plus</span>
<span class="ot">mkMult ::</span> <span class="dt">Expr</span> <span class="ot">-></span> [<span class="dt">Expr</span>] <span class="ot">-></span> <span class="dt">Expr</span>
mkMult <span class="fu">=</span> foldl <span class="dt">Mult</span>
<span class="ot">parseExpr ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span>
parseExpr <span class="fu">=</span> recNonTerminal <span class="st">"expr"</span> <span class="fu">$</span> \ exp <span class="ot">-></span>
ePlus exp
<span class="ot">ePlus ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span> <span class="ot">-></span> f <span class="dt">Expr</span>
ePlus exp <span class="fu">=</span> nonTerminal <span class="st">"plus"</span> <span class="fu">$</span>
mkPlus <span class="fu"><$></span> eMult exp
<span class="fu"><*></span> many (spaces <span class="fu">*></span> char <span class="ch">'+'</span> <span class="fu">*></span> spaces <span class="fu">*></span> eMult exp)
<span class="fu"><*</span> spaces
<span class="ot">eMult ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span> <span class="ot">-></span> f <span class="dt">Expr</span>
eMult exp <span class="fu">=</span> nonTerminal <span class="st">"mult"</span> <span class="fu">$</span>
mkPlus <span class="fu"><$></span> eAtom exp
<span class="fu"><*></span> many (spaces <span class="fu">*></span> char <span class="ch">'*'</span> <span class="fu">*></span> spaces <span class="fu">*></span> eAtom exp)
<span class="fu"><*</span> spaces
<span class="ot">eAtom ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span> <span class="ot">-></span> f <span class="dt">Expr</span>
eAtom exp <span class="fu">=</span> nonTerminal <span class="st">"atom"</span> <span class="fu">$</span>
aConst <span class="ot">`orElse`</span> eParens exp
<span class="ot">aConst ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span>
aConst <span class="fu">=</span> nonTerminal <span class="st">"const"</span> <span class="fu">$</span> <span class="dt">Const</span> <span class="fu">.</span> read <span class="fu"><$></span> many1 digit
<span class="ot">eParens ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f a <span class="ot">-></span> f a
eParens inner <span class="fu">=</span>
id <span class="fu"><$</span> char <span class="ch">'('</span>
<span class="fu"><*</span> spaces
<span class="fu"><*></span> inner
<span class="fu"><*</span> spaces
<span class="fu"><*</span> char <span class="ch">')'</span>
<span class="fu"><*</span> spaces</code></pre></div>
<p>And indeed, this works:</p>
<pre><code>*Main> putStr $ ppGrammar "expr" parseExpr
const = digit, {digit};
spaces = {' ' | newline};
atom = const | '(', spaces, expr, spaces, ')', spaces;
mult = atom, {spaces, '*', spaces, atom}, spaces;
plus = mult, {spaces, '+', spaces, mult}, spaces;
expr = plus;</code></pre>
<h3 id="recursion-variant-2">Recursion (variant 2)</h3>
<p>Interestingly, there is another solution to this problem, which avoids introducing <code>recNonTerminal</code> and explicitly passing around the recursive call (i.e. the <code>exp</code> in the example). To implement that we have to adjust our <code>Grammar</code> type as follows:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">Grammar</span> a <span class="fu">=</span> <span class="dt">G</span> ([<span class="dt">String</span>] <span class="ot">-></span> (<span class="dt">BNF</span>, <span class="dt">RHS</span>))</code></pre></div>
<p>The idea is that the list of strings is those non-terminals that we are currently defining. So in <code>nonTerminal</code>, we check if the non-terminal to be introduced is currently in the process of being defined, and then simply ignore the body. This way, the recursion is stopped automatically:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">nonTerminalG ::</span> <span class="dt">String</span> <span class="ot">-></span> (<span class="dt">Grammar</span> a) <span class="ot">-></span> <span class="dt">Grammar</span> a
nonTerminalG name (<span class="dt">G</span> g) <span class="fu">=</span> <span class="dt">G</span> <span class="fu">$</span> \seen <span class="ot">-></span>
<span class="kw">if</span> name <span class="ot">`elem`</span> seen
<span class="kw">then</span> ([], <span class="dt">NonTerminal</span> name)
<span class="kw">else</span> <span class="kw">let</span> (prods, rhs) <span class="fu">=</span> g (name <span class="fu">:</span> seen)
<span class="kw">in</span> (prods <span class="fu">++</span> [(name, rhs)], <span class="dt">NonTerminal</span> name)</code></pre></div>
<p>After adjusting the other primitives of <code>Grammar</code> (including the <code>Functor</code> and <code>Applicative</code> instances, wich now again have <code>nonTerminal</code>) to type-check again, we observe that this parser/grammar generator for expressions, with genuine recursion, works now:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">parseExp ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span>
parseExp <span class="fu">=</span> nonTerminal <span class="st">"expr"</span> <span class="fu">$</span>
ePlus
<span class="ot">ePlus ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span>
ePlus <span class="fu">=</span> nonTerminal <span class="st">"plus"</span> <span class="fu">$</span>
mkPlus <span class="fu"><$></span> eMult
<span class="fu"><*></span> many (spaces <span class="fu">*></span> char <span class="ch">'+'</span> <span class="fu">*></span> spaces <span class="fu">*></span> eMult)
<span class="fu"><*</span> spaces
<span class="ot">eMult ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span>
eMult <span class="fu">=</span> nonTerminal <span class="st">"mult"</span> <span class="fu">$</span>
mkPlus <span class="fu"><$></span> eAtom
<span class="fu"><*></span> many (spaces <span class="fu">*></span> char <span class="ch">'*'</span> <span class="fu">*></span> spaces <span class="fu">*></span> eAtom)
<span class="fu"><*</span> spaces
<span class="ot">eAtom ::</span> <span class="dt">Descr</span> f <span class="ot">=></span> f <span class="dt">Expr</span>
eAtom <span class="fu">=</span> nonTerminal <span class="st">"atom"</span> <span class="fu">$</span>
aConst <span class="ot">`orElse`</span> eParens parseExp</code></pre></div>
<p>Note that the recursion is only going to work if there is at least one call to <code>nonTerminal</code> somewhere around the recursive calls. We still cannot implement <code>many</code> as naively as above.</p>
<h3 id="homework">Homework</h3>
<p>If you want to play more with this: The <a href="http://cis.upenn.edu/~cis194/fall16/hw/09-more-applicative.html">homework</a> is to define a parser/grammar-generator for EBNF itself, as specified in this variant:</p>
<pre><code>identifier = letter, {letter | digit | '-'};
spaces = {' ' | newline};
quoted-char = non-quote-or-backslash | '\\', '\\' | '\\', '\'';
terminal = '\'', {quoted-char}, '\'', spaces;
non-terminal = identifier, spaces;
option = '[', spaces, rhs, spaces, ']', spaces;
repetition = '{', spaces, rhs, spaces, '}', spaces;
group = '(', spaces, rhs, spaces, ')', spaces;
atom = terminal | non-terminal | option | repetition | group;
sequence = atom, {spaces, ',', spaces, atom}, spaces;
choice = sequence, {spaces, '|', spaces, sequence}, spaces;
rhs = choice;
production = identifier, spaces, '=', spaces, rhs, ';', spaces;
bnf = production, {production};</code></pre>
<p>This grammar is set up so that the precedence of <code>,</code> and <code>|</code> is correctly implemented: <code>a , b | c</code> will parse as <code>(a, b) | c</code>.</p>
<p>In this syntax for BNF, terminal characters are quoted, i.e. inside <code>'…'</code>, a <code>'</code> is replaced by <code>\'</code> and a <code>\</code> is replaced by <code>\\</code> – this is done by the function <code>quote</code> in <code>ppRHS</code>.</p>
<p>If you do this, you should able to round-trip with the pretty-printer, i.e. parse back what it wrote:</p>
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> <span class="kw">let</span> bnf1 <span class="fu">=</span> runGrammer <span class="st">"expr"</span> parseExpr
<span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> <span class="kw">let</span> bnf2 <span class="fu">=</span> runGrammer <span class="st">"expr"</span> parseBNF
<span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> <span class="kw">let</span> f <span class="fu">=</span> Data.Maybe.fromJust <span class="fu">.</span> parse parseBNF<span class="fu">.</span> ppBNF
<span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> f bnf1 <span class="fu">==</span> bnf1
<span class="dt">True</span>
<span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> f bnf2 <span class="fu">==</span> bnf2
<span class="dt">True</span></code></pre></div>
<p>The last line is quite meta: We are using <code>parseBNF</code> as a parser on the pretty-printed grammar produced from interpreting <code>parseBNF</code> as a grammar.</p>
<h3 id="conclusion">Conclusion</h3>
<p>We have again seen an example of the excellent support for abstraction in Haskell: Being able to define so very different things such as a parser and a grammar description with the same code is great. Type classes helped us here.</p>
<p>Note that it was crucial that our combined parser/grammars are only able to use the methods of <code>Applicative</code>, and <em>not</em> <code>Monad</code>. <code>Applicative</code> is less powerful, so by giving less power to the user of our <code>Descr</code> interface, the other side, i.e. the implementation, can be more powerful.</p>
<p>The reason why <code>Applicative</code> is ok, but <code>Monad</code> is not, is that in <code>Applicative</code>, the <em>results do not affect the shape of the computation</em>, whereas in <code>Monad</code>, the whole point of the bind operator <code>(>>=)</code> is that <em>the result of the computation is used to decide the next computation</em>. And while this is perfectly fine for a parser, it just makes no sense for a grammar generator, where there simply are no values around!</p>
<p>We have also seen that a phantom type, namely the parameter of <code>Grammar</code>, can be useful, as it lets the type system make sure we do not write nonsense. For example, the type of <code>orElseG</code> ensures that both grammars that are combined here indeed describe something of the same type.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>It seems to be the week of applicative-appraising blog posts: Brent has posted a nice piece about <a href="https://byorgey.wordpress.com/2016/10/25/adventures-in-enumerating-balanced-brackets/">enumerations using <code>Applicative</code></a> yesterday.<a href="#fnref1">↩</a></p></li>
<li id="fn2"><p>I like how in this alignment of <code><*></code> and <code><*</code> the <code>></code> point out where the arguments are that are being passed to the function on the left.<a href="#fnref2">↩</a></p></li>
</ol>
</div>Wed, 26 Oct 2016 00:00:00 -0400