Verifying purely functional programs
More interactive than last time!
Verifying list-manipulating programs
type list (a:Type) =
| Nil : list a
| Cons : hd:a -> tl:list a -> list a
module RefinedStack
abstract type stack = list int
abstract val is_empty : stack -> Tot bool
let is_empty = Nil?
abstract val empty : s:stack{is_empty s}
let empty = []
abstract val push : int -> stack -> Tot (s:stack{~(is_empty s)})
let push x xs = Cons x xs
abstract val pop : s:stack{~(is_empty s)} -> Tot stack
let pop = Cons?.tl
abstract val top : s:stack{~(is_empty s)} -> Tot int
let top = Cons?.hd
module RefinedStackClient
open RefinedStack
let main() : Tot stack =
let s = push 1 (push 2 (push 3 empty)) in
let t = top s in
let s' = pop s in s'
(* pop s' -- Subtyping check failed;
expected type (s:stack{~(is_empty s)}); got type stack *)
RefinedStack
interface so that this code works
module AppIntrinsic
open FStar.List.Tot
let rec append (#a:Type) (xs : list a) (ys : list a) : Tot (list a) =
match xs with
| [] -> ys
| x :: xs' -> x :: append xs' ys
let rec append' (#a:Type) (xs : list a) (ys : list a) : Pure (list a)
(requires True) (ensures (fun zs -> length zs = length xs + length ys)) =
match xs with
| [] -> ys
| x :: xs' -> x :: append' xs' ys
module AppExtrinsic
open FStar.List.Tot
let rec append (#a:Type) (xs : list a) (ys : list a) : Tot (list a) =
match xs with
| [] -> ys
| x :: xs' -> x :: append xs' ys
let rec append_length (#a:Type) (xs : list a) (ys : list a) : Pure unit
(requires True)
(ensures (fun _ -> length (append xs ys) = length xs + length ys)) =
match xs with
| [] -> ()
| x :: xs' -> append_length xs' ys
let rec append_length_lemma (#a:Type) (xs : list a) (ys : list a) : Lemma
(ensures (length (append xs ys) = length xs + length ys)) =
match xs with
| [] -> ()
| x :: xs' -> append_length xs' ys
module Rev
open AppExtrinsic
let snoc l h = append l [h]
val reverse: #a:Type -> list a -> Tot (list a)
let rec reverse (#a:Type) l =
match l with
| [] -> []
| hd::tl -> snoc (reverse tl) hd
val snoc_cons: #a:Type -> l:list a -> h:a ->
Lemma (reverse (snoc l h) == h::reverse l)
let rec snoc_cons (#a:Type) l h =
match l with
| [] -> ()
| hd::tl -> snoc_cons tl h
val rev_involutive: #a:Type -> l:list a -> Lemma (reverse (reverse l) == l)
let rec rev_involutive (#a:Type) l =
match l with
| [] -> ()
| hd::tl -> rev_involutive tl; snoc_cons (reverse tl) hd
Homework: Binary Search Tree
in 1 week: Verified Low-Level Programming Embedded in F* (Jonathan Protzenko)
in 2 weeks: From “Hoare Logic” to “Dijkstra Monads for Free”
in 3-4 weeks: Verifying Crypto Implementations in F* (Karthik)