Keep calm and use Coq
Alexander Tchitchigin
Typeable.io
Typical Coq

Dependent types are extension
Do not pay for what you do not use!
Translation to ML
- Definition ==> let
- Fixpoint ==> let rec
- fun ==> fn
- fix ==> fn rec
- Inductive ==> datatype
The most functional program :)
Require Import Init.
Require Import Coq.Arith.PeanoNat.
Fixpoint fact (n : nat) : nat :=
match n with
| 0 => 1
| S m => n * (fact m)
end.
Compute (fact 5).
(*
= 120
: nat
*)
Extraction Language Haskell.
Extraction fact.
(*
fact :: Nat -> Nat
fact n =
case n of {
O -> S O;
S m -> mul n (fact m)}
*)The lists
Require Import Lists.List.
Import ListNotations.
Fixpoint append {A} (xs ys : list A) : list A :=
match xs with
| [] => ys
| x :: xs1 => x :: append xs1 ys
end.
Compute (append [1; 2; 3] [4; 5]).
(*
= [1; 2; 3; 4; 5]
: list nat
*)
Extraction append.
(*
append :: (List A) -> (List A) -> List A
append xs ys =
case xs of {
Nil -> ys;
Cons x xs1 -> Cons x (append xs1 ys)}
*)The lists reversed
Definition reverse {A} : list A -> list A.
refine(
fix F (xs : list A) :=
match xs with
| [] => _
| x :: xs1 => append (F _) (_ :: [])
end
);
auto.
Defined.
Compute (reverse (append [1; 2; 3] [4; 5])).
(*
= [5; 4; 3; 2; 1]
: list nat
*)
Extraction reverse.
(*
reverse :: (List A) -> List A
reverse xs =
case xs of {
Nil -> xs;
Cons x xs1 -> append (reverse xs1) (Cons x Nil)}
*)The proofs! :)
Lemma append_nil : forall (A : Type) (xs : list A), append xs [] = xs.
Proof.
intros.
induction xs; simpl.
- reflexivity.
- rewrite IHxs. reflexivity.
Qed.
Lemma append_assoc :
forall (A : Type) (xs ys zs : list A),
append (append xs ys) zs = append xs (append ys zs).
Proof.
intros.
induction xs; simpl.
- reflexivity.
- rewrite IHxs. reflexivity.
Qed.The spec! :)
Lemma rev_append :
forall (A : Type) (xs ys : list A),
reverse (append xs ys) = append (reverse ys) (reverse xs).
Proof.
intros.
induction xs; simpl.
- rewrite append_nil. reflexivity.
- rewrite IHxs. rewrite append_assoc. reflexivity.
Qed.
Theorem rev_rev : forall (A : Type) (xs : list A), reverse (reverse xs) = xs.
Proof.
intros.
induction xs; simpl.
- reflexivity.
- rewrite rev_append. rewrite IHxs. simpl. reflexivity.
Qed.Trie
Inductive trie (A V : Type) :=
| Trie : option V -> list (A * trie A V) -> trie A V.
Definition value {A} {V} (t : trie A V) : option V :=
match t with
| Trie _ _ ov _ => ov
end.
Definition alist {A} {V} (t : trie A V) : list (A * trie A V) :=
match t with
| Trie _ _ _ al => al
end.
Definition assoc {K} {V} : (K -> K -> bool) -> list (K * V) -> K -> option V.
refine(
fix F (eqb : K -> K -> bool) (l : list (K * V)) (k : K) :=
match l with
| [] => None
| p :: ps => if eqb (fst p) k then Some (snd p) else _
end
); auto.
Defined.Operations
Definition lookup {A} {V} : (A -> A -> bool) -> trie A V -> list A -> option V.
refine(
fix F (eqb : A -> A -> bool) (t : trie A V) (l : list A) :=
match l with
| [] => None
| x :: xs => match assoc _ (alist _) x with
| None => None
| Some t1 => F _ t1 _
end
end
); auto.
Defined.
Definition update {A} {V} :
(A -> A -> bool) -> trie A V -> list A -> V -> trie A V.
simple refine(
fix F (eqb : A -> A -> bool) (t : trie A V) (l : list A) (v : V) {struct l} :=
match l with
| [] => Trie _ _ (Some v) (alist t)
| x :: xs =>
let tt := match assoc _ (alist t) _ with
| None => Trie _ _ None []
| Some t1 => t1
end
in Trie _ _ (value t) ( (_, F _ _ _ _) :: alist t)
end
); auto.
Defined.Extraction
Extract Inductive bool => "Bool" [ "True" "False" ].
Extract Inductive prod => "(,)" [ "(,)" ].
Extract Inductive list => "List" [ "[]" "(:)" ].
Extract Inductive option => "Maybe" [ "Just" "Nothing" ].
Extract Constant fst => "fst".
Extract Constant snd => "snd".
Recursive Extraction lookup update.Extraction
module Main where
import qualified Prelude
fst :: ((,) a1 a2) -> a1
fst = fst
snd :: ((,) a1 a2) -> a2
snd = snd
data Trie a v =
Trie0 (Maybe v) (List ((,) a (Trie a v)))
value :: (Trie a1 a2) -> Maybe a2
value t =
case t of {
Trie0 ov _ -> ov}
alist :: (Trie a1 a2) -> List ((,) a1 (Trie a1 a2))
alist t =
case t of {
Trie0 _ al -> al}
assoc :: (a1 -> a1 -> Bool) -> (List ((,) a1 a2)) -> a1 -> Maybe a2
assoc eqb l k =
case l of {
[] -> Nothing;
(:) p ps ->
case eqb (fst p) k of {
True -> Just (snd p);
False -> assoc eqb ps k}}Extraction
lookup :: (a1 -> a1 -> Bool) -> (Trie a1 a2) -> (List a1) -> Maybe a2
lookup eqb t l =
case l of {
[] -> Nothing;
(:) x xs ->
case assoc eqb (alist t) x of {
Just t1 -> lookup eqb t1 xs;
Nothing -> Nothing}}
update :: (a1 -> a1 -> Bool) -> (Trie a1 a2) -> (List a1) -> a2 -> Trie a1 a2
update eqb t l v =
case l of {
[] -> Trie0 (Just v) (alist t);
(:) x xs ->
let {
tt = case assoc eqb (alist t) x of {
Just t1 -> t1;
Nothing -> Trie0 Nothing []}}
in
Trie0 (value t) ((:) ((,) x (update eqb tt xs v)) (alist t))}Inspiring examples
- http://compcert.inria.fr/
- Verified C compiler
- x86, x86_64, ARM, PowerPC (32 and 64)
- Detects undefined behaviours
- https://deepspec.org/
- Verified everything: ISA, compiler, OS, apps
- Microsoft, Intel, Google, Facebook, Amazon
- https://github.com/uhub/awesome-coq
- EVM for instance :)
Literature
- Software Foundations
- https://softwarefoundations.cis.upenn.edu/current/index.html
- 3 Volumes + 2 in work
- Certified Programming with Dependent Types
- http://adam.chlipala.net/cpdt/
How I Learned to Stop Worrying and Love the Coq
By Alexander Letov
How I Learned to Stop Worrying and Love the Coq
- 90