(** * Maps: Total and Partial Maps *)
(** This file is almost identical to the [Maps] chapter of Software Foundations volume 1 (Logical Foundations), except that it implements functions from [nat] to [A] rather than functions from [id] to [A].  Maps (or dictionaries) are ubiquitous data structures, both in software construction generally and in the theory of programming languages in particular; we're going to need them in many places in the coming chapters.  They also make a nice case study using ideas we've seen in previous chapters, including building data structures out of higher-order functions (from [Basics] and [Poly]) and the use of reflection to streamline proofs (from [IndProp]).  We'll define two flavors of 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 *)
(** One small digression before we start.  Unlike the chapters we have seen so far, this one does not [Require Import] the chapter before it (and, transitively, all the earlier chapters).  Instead, in this chapter and from now, on we're going to import the definitions and theorems we need directly from Coq's standard library stuff.  You should not notice much difference, though, because we've been careful to name our own definitions and theorems the same as their counterparts in the standard library, wherever they overlap. *)
(** Documentation for the standard library can be found at http://coq.inria.fr/library/.  The [Search] command is a good way to look for theorems involving objects of specific types. *)
(* ################################################################# *)
(** * Total Maps *)
(** Our main job in this chapter will be to build a definition of partial maps that is similar in behavior to the one we saw in the [Lists] chapter, plus accompanying lemmas about their behavior.  This time around, though, we're going to use _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.  We build partial maps in two steps.  First, we define a type of _total maps_ that return a default value when we look up a key that is not present in the map. *)
Definition total_map (A:Type) := nat -> A.
(** Intuitively, a total map over an element type [A] _is_ just a function that can be used to look up [id]s, yielding [A]s.  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. *)
Definition t_empty {A:Type} (v : A) : total_map A :=
(fun _ => v).
(** 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 : nat) (v : A) :=
fun x' => if beq_nat x x' then v else m x'.
(** This definition is a nice example of higher-order programming. The [t_update] function takes a _function_ [m] and yields a new function [fun x' => ...] that behaves like the desired map.  For example, we can build a map taking [id]s to [bool]s, where [Id 3] is mapped to [true] and every other key is mapped to [false], like this: *)
Definition examplemap :=
t_update (t_update (t_empty false) 1 false) 3 true.
(** 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 0 = false.

Theorem update_permute : forall (X:Type) v1 v2 x1 x2
(m : partial_map X),
x2 <> x1 ->
(update (update m x2 v2) x1 v1)
= (update (update m x1 v1) x2 v2).