# MapsTotal and Partial Maps

*total*maps, which include a "default" element to be returned when a key being looked up doesn't exist, and

*partial*maps, which return an option to indicate success or failure. The latter is defined in terms of the former, using None as the default element.

# The Coq Standard Library

Require Import Coq.Arith.Arith.

Require Import Coq.Bool.Bool.

Require Import Coq.Logic.FunctionalExtensionality.

Documentation for the standard library can be found at
http://coq.inria.fr/library/.
The SearchAbout command is a good way to look for theorems
involving objects of specific types.

# Identifiers

Inductive id : Type :=

| Id : nat → id.

Definition beq_id id

_{1}id

_{2}:=

match id

_{1},id

_{2}with

| Id n

_{1}, Id n

_{2}⇒ beq_nat n

_{1}n

_{2}

end.

Theorem beq_id_refl : ∀id, true = beq_id id id.

(In the HTML version, the proof of this theorem is elided, since
the details are pretty routine at this point. Click on the box if
you want to see it.)
The following useful property of beq_id follows from an
analogous lemma about numbers:

Theorem beq_id_true_iff : ∀id

_{1}id

_{2}: id,

beq_id id

_{1}id

_{2}= true ↔ id

_{1}= id

_{2}.

Proof.

intros [n

unfold beq_id.

rewrite beq_nat_true_iff.

split.

- (* -> *) intros H. rewrite H. reflexivity.

- (* <- *) intros H. inversion H. reflexivity.

Qed.

intros [n

_{1}] [n_{2}].unfold beq_id.

rewrite beq_nat_true_iff.

split.

- (* -> *) intros H. rewrite H. reflexivity.

- (* <- *) intros H. inversion H. reflexivity.

Qed.

Similarly:

This useful variant follows just by rewriting:

# Total Maps

*functions*, rather than lists of key-value pairs, to build maps. The advantage of this representation is that it offers a more

*extensional*view of maps, where two maps that respond to queries in the same way will be represented as literally the same thing (the same function), rather than just "equivalent" data structures. This, in turn, simplifies proofs that use maps.

*total maps*that return a default value when we look up a key that is not present in the map.

Intuitively, a total map over an element type A
The function t_empty yields an empty total map, given a default
element; this map always returns the default element when applied
to any id.

*is*just a function that can be used to look up ids, yielding As.
More interesting is the update function, which (as before) takes
a map m, a key x, and a value v and returns a new map that
takes x to v and takes every other key to whatever m does.

Definition t_update {A:Type} (m : total_map A)

(x : id) (v : A) :=

fun x' ⇒ if beq_id x x' then v else m x'.

This definition is a nice example of higher-order programming.
The t_update function takes a
For example, we can build a map taking ids to bools, where Id
3 is mapped to true and every other key is mapped to false,
like this:

*function*m and yields a new function fun x' ⇒ ... that behaves like the desired map.
This completes the definition of total maps. Note that we don't
need to define a find operation because it is just function
application!

Example update_example1 : examplemap (Id 0) = false.

Proof. reflexivity. Qed.

Example update_example2 : examplemap (Id 1) = false.

Proof. reflexivity. Qed.

Example update_example3 : examplemap (Id 2) = false.

Proof. reflexivity. Qed.

Example update_example4 : examplemap (Id 3) = true.

Proof. reflexivity. Qed.

To use maps in later chapters, we'll need several fundamental
facts about how they behave. Even if you don't work the following
exercises, make sure you thoroughly understand the statements of
the lemmas! (Some of the proofs require the functional
extensionality axiom discussed in the Logic chapter, which is
also included in the standard library.)

#### Exercise: 2 stars, optional (t_update_eq)

First, if we update a map m at a key x with a new value v and then look up x in the map resulting from the update, we get back v:Lemma t_update_eq : ∀A (m: total_map A) x v,

(t_update m x v) x = v.

Proof.

(* FILL IN HERE *) Admitted.

☐

#### Exercise: 2 stars, optional (t_update_neq)

On the other hand, if we update a map m at a key x_{1}and then look up a*different*key x_{2}in the resulting map, we get the same result that m would have given:Theorem t_update_neq : ∀(X:Type) v x

_{1}x

_{2}

(m : total_map X),

x

_{1}≠ x

_{2}→

(t_update m x

_{1}v) x

_{2}= m x

_{2}.

Proof.

(* FILL IN HERE *) Admitted.

☐

#### Exercise: 2 stars, optional (t_update_shadow)

If we update a map m at a key x with a value v_{1}and then update again with the same key x and another value v_{2}, the resulting map behaves the same (gives the same result when applied to any key) as the simpler map obtained by performing just the second update on m:Lemma t_update_shadow : ∀A (m: total_map A) v

_{1}v

_{2}x,

t_update (t_update m x v

_{1}) x v

_{2}

= t_update m x v

_{2}.

Proof.

(* FILL IN HERE *) Admitted.

☐
For the final two lemmas about total maps, it's convenient to use
the reflection idioms introduced in chapter IndProp. We begin
by proving a fundamental

*reflection lemma*relating the equality proposition on ids with the boolean function beq_id.#### Exercise: 2 stars (beq_idP)

Use the proof of beq_natP in chapter IndProp as a template to prove the following:
☐
Now, given ids x

_{1}and x_{2}, we can use the destruct (beq_idP x_{1}x_{2}) to simultaneously perform case analysis on the result of beq_id x_{1}x_{2}and generate hypotheses about the equality (in the sense of =) of x_{1}and x_{2}.#### Exercise: 2 stars (t_update_same)

Using the example in chapter IndProp as a template, use beq_idP to prove the following theorem, which states that if we update a map to assign key x the same value as it already has in m, then the result is equal to m:Theorem t_update_same : ∀X x (m : total_map X),

t_update m x (m x) = m.

Proof.

(* FILL IN HERE *) Admitted.

☐

#### Exercise: 3 stars, recommended (t_update_permute)

Use beq_idP to prove one final property of the update function: If we update a map m at two distinct keys, it doesn't matter in which order we do the updates.Theorem t_update_permute : ∀(X:Type) v

_{1}v

_{2}x

_{1}x

_{2}

(m : total_map X),

x

_{2}≠ x

_{1}→

(t_update (t_update m x

_{2}v

_{2}) x

_{1}v

_{1})

= (t_update (t_update m x

_{1}v

_{1}) x

_{2}v

_{2}).

Proof.

(* FILL IN HERE *) Admitted.

☐

# Partial maps

*partial maps*on top of total maps. A partial map with elements of type A is simply a total map with elements of type option A and default element None.

Definition partial_map (A:Type) := total_map (option A).

Definition empty {A:Type} : partial_map A :=

t_empty None.

Definition update {A:Type} (m : partial_map A)

(x : id) (v : A) :=

t_update m x (Some v).

We can now lift all of the basic lemmas about total maps to
partial maps.

Lemma update_eq : ∀A (m: partial_map A) x v,

(update m x v) x = Some v.

Theorem update_neq : ∀(X:Type) v x

_{1}x

_{2}

(m : partial_map X),

x

_{2}≠ x

_{1}→

(update m x

_{2}v) x

_{1}= m x

_{1}.

Lemma update_shadow : ∀A (m: partial_map A) v

_{1}v

_{2}x,

update (update m x v

_{1}) x v

_{2}= update m x v

_{2}.

Theorem update_same : ∀X v x (m : partial_map X),

m x = Some v →

update m x v = m.

Theorem update_permute : ∀(X:Type) v

_{1}v

_{2}x

_{1}x

_{2}

(m : partial_map X),

x

_{2}≠ x

_{1}→

(update (update m x

_{2}v

_{2}) x

_{1}v

_{1})

= (update (update m x

_{1}v

_{1}) x

_{2}v

_{2}).