Ordered association lists #
OrderedAssocList is a wrapper around AssocList,
with the additional invariant that the keys are in strictly increasing order.
As a consequence, an OrderedAssocList is determined by the lookup function l[x]?, that is
(∀ a, l₁[a]? = l₂[a]?) → l₁ = l₂
and this makes proving identities between operations much easier than with AssocList.
As the operations on OrderedAssocList are defined in terms of AssocList,
they evaluate in the kernel, but inherit the O(n) time complexity
(i.e. are not suitable for large data). Their advantage relative to an ordered map is the
simple extensionality property above.
We will later add another wrapper requiring that a "default" value does not appear, so e.g. finitely supported functions can be uniquely represented.
The main operations defined are:
l[x]?, which linearly searches the list, stopping if the keys get too large.insert, which inserts a new key-value pair, maintaining the order invariant.filterMapVal f, forf : α → β → Option γ, which applies a function to values, dropping some values.merge fforf : α → Option β → Option γ → Option δwhich merges two lists, dropping some values. It runs in timeO(l₁.length + l₂.length).
We first define some predicates and operations in the AssocList namespace.
The head key of an AssocList, or none if the list is empty.
Equations
- Batteries.AssocList.nil.headKey? = none
- (Batteries.AssocList.cons a value tail).headKey? = some a
Instances For
The condition that an element is less than the first key of an AssocList, or that list is empty.
Equations
- Batteries.AssocList.LTHeadKey cmp a t = match t.headKey? with | none => True | some x => cmp a x = Ordering.lt
Instances For
The predicate that the keys of an AssocList are
in strictly increasing order according to the comparator cmp.
Equations
- Batteries.AssocList.KeysOrdered cmp Batteries.AssocList.nil = True
- Batteries.AssocList.KeysOrdered cmp (Batteries.AssocList.cons a value tail) = (Batteries.AssocList.LTHeadKey cmp a tail ∧ Batteries.AssocList.KeysOrdered cmp tail)
Instances For
A relation on two AssocLists, asserting that the head key of the first list is at most
the head key of the second list, or that the second list is empty.
Equations
Instances For
Ordered-respecting operations on AssocList #
We now define orderedInsert, and orderedMerge,
which will later be wrapped as OrderedAssocList.insert and OrderedAssocList.merge.
We prove that with KeysOrdered input these functions produce KeysOrdered outputs.
We prove the same about AssocList.filterMapVal.
Insert a key-value pair into an AssocList,
in such a way that if the original list has keys in increasing order,
so does the result.
(Otherwise, it is inserted before the first key the new key is smaller than,
or replaces the first key the new key is equal to.)
We later wrap this as OrderedAssocList.insert.
Equations
- One or more equations did not get rendered due to their size.
- Batteries.AssocList.orderedInsert cmp Batteries.AssocList.nil a b = Batteries.AssocList.cons a b Batteries.AssocList.nil
Instances For
Merge two AssocLists,
at each stage taking the first key-value pair from whichever list has a smaller first key.
If both inputs have keys in strictly increasing order, so does the result.
(We later wrap this as OrderedAssocList.merge.)
We combine values using a function f : α → Option β → Option γ → Option δ which we call as
f a (some b) none when encountering a key present only in the first list (with value b),
f a none (some g) when encountering a key present only in the second list (with value g), and
f a (some b) (some g) when encountering a key present in both lists.
(Note the value of f a none none is never used.)
Equations
- One or more equations did not get rendered due to their size.
- Batteries.AssocList.orderedMerge cmp f Batteries.AssocList.nil Batteries.AssocList.nil = Batteries.AssocList.nil
Instances For
Find the value associated to a key by traversing left to right, short-circuiting once we are considering larger keys.
Equations
- One or more equations did not get rendered due to their size.
- Batteries.AssocList.orderedFind? cmp Batteries.AssocList.nil x = none
Instances For
If two AssocLists have ordered keys
we can check whether they are equal by checking if their orderedFind? functions are equal.
An OrderedAssocList is an AssocList with the additional invariant that
the keys are in strictly increasing order according to some specified comparator function.
- toAssocList : AssocList α β
The underlying
AssocListof anOrderedAssocList. - keysOrdered : AssocList.KeysOrdered cmp self.toAssocList
The invariant that the keys are in strictly increasing order according to
cmp.
Instances For
The empty OrderedAssocList.
Equations
- Batteries.OrderedAssocList.nil = { toAssocList := Batteries.AssocList.nil, keysOrdered := trivial }
Instances For
The length of an OrderedAssocList.
Equations
- l.length = l.toAssocList.length
Instances For
The first key-value pair in an OrderedAssocList.
Equations
Instances For
The tail of an OrderedAssocList.
Equations
- { toAssocList := Batteries.AssocList.nil, keysOrdered := keysOrdered }.tail = { toAssocList := Batteries.AssocList.nil, keysOrdered := keysOrdered }
- { toAssocList := Batteries.AssocList.cons a b tail, keysOrdered := keysOrdered }.tail = { toAssocList := tail, keysOrdered := ⋯ }
Instances For
Find the value associated to a key by traversing left to right, short-circuiting once we are considering larger keys.
This is the internal implementation of l[x]?, which should be preferred.
Equations
- l.find? x = Batteries.AssocList.orderedFind? cmp l.toAssocList x
Instances For
Check if an OrderedAssocList contains a specific key.
Instances For
Equations
- One or more equations did not get rendered due to their size.
The first key in an OrderedAssocList, or none if the list is empty.
Equations
- l.headKey? = l.toAssocList.headKey?
Instances For
Either a is less than the first key of l, or l is empty.
Equations
Instances For
The head key of a tail is either none, or greater than the original head key.
Prepend a key-value pair, requiring a proof that the key is smaller than the existing smallest key.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Insert a key-value pair into an OrderedAssocList.
This replaces the current value if the key is already present,
and otherwise inserts it before the first key which is greater than the inserted key.
Equations
- l.insert a b = { toAssocList := Batteries.AssocList.orderedInsert cmp l.toAssocList a b, keysOrdered := ⋯ }
Instances For
Apply a function to each key-value pair,
either replacing the value or dropping it if the function returns none.
Equations
- Batteries.OrderedAssocList.filterMapVal f l = { toAssocList := Batteries.AssocList.filterMapVal f l.toAssocList, keysOrdered := ⋯ }
Instances For
Merge two OrderedAssocLists using a function α → Option β → Option γ → Option δ,
dropping values where the function returns none.
Equations
- Batteries.OrderedAssocList.merge f l₁ l₂ = { toAssocList := Batteries.AssocList.orderedMerge cmp f l₁.toAssocList l₂.toAssocList, keysOrdered := ⋯ }
Instances For
Add two OrderedAssocLists, taking the value from one list if the other value is missing.
(That is, treating missing values as 0.)
Equations
- l₁.add l₂ = Batteries.OrderedAssocList.merge (fun (x : α) => Batteries.OrderedAssocList.add.addOption) l₁ l₂
Instances For
Add two values, treating missing values as 0.
Equations
Instances For
Multiply two OrderedAssocLists,
dropping any values where the corresponding value in the other list is missing.
(That is, treating missing values as 0.)
Equations
- l₁.mul l₂ = Batteries.OrderedAssocList.merge (fun (x : α) => Batteries.OrderedAssocList.mul.mulOption) l₁ l₂
Instances For
Multiply two values, treating missing values as 0.