/- Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura -/ universes u /-- A difference list is a function that, given a list, returns the original contents of the difference list prepended to the given list. This structure supports `O(1)` `append` and `concat` operations on lists, making it useful for append-heavy uses such as logging and pretty printing. -/ structure dlist (α : Type u) := (apply : list α → list α) (invariant : ∀ l, apply l = apply [] ++ l) namespace dlist open function variables {α : Type u} local notation `♯`:max := by abstract {intros, rsimp} /-- Convert a list to a dlist -/ def of_list (l : list α) : dlist α := ⟨append l, ♯⟩ /-- Convert a dlist to a list -/ def to_list : dlist α → list α | ⟨xs, _⟩ := xs [] /-- Create a dlist containing no elements -/ def empty : dlist α := ⟨id, ♯⟩ local notation a `::_`:max := list.cons a /-- Create dlist with a single element -/ def singleton (x : α) : dlist α := ⟨x::_, ♯⟩ local attribute [simp] function.comp /-- `O(1)` Prepend a single element to a dlist -/ def cons (x : α) : dlist α → dlist α | ⟨xs, h⟩ := ⟨x::_ ∘ xs, ♯⟩ /-- `O(1)` Append a single element to a dlist -/ def concat (x : α) : dlist α → dlist α | ⟨xs, h⟩ := ⟨xs ∘ x::_, ♯⟩ /-- `O(1)` Append dlists -/ protected def append : dlist α → dlist α → dlist α | ⟨xs, h₁⟩ ⟨ys, h₂⟩ := ⟨xs ∘ ys, ♯⟩ instance : has_append (dlist α) := ⟨dlist.append⟩ local attribute [simp] of_list to_list empty singleton cons concat dlist.append lemma to_list_of_list (l : list α) : to_list (of_list l) = l := by cases l; simp lemma of_list_to_list (l : dlist α) : of_list (to_list l) = l := begin cases l with xs, assert h : append (xs []) = xs, {intros, apply funext, intros x, simp [invariant x]}, simp [h] end lemma to_list_empty : to_list (@empty α) = [] := by simp lemma to_list_singleton (x : α) : to_list (singleton x) = [x] := by simp lemma to_list_append (l₁ l₂ : dlist α) : to_list (l₁ ++ l₂) = to_list l₁ ++ to_list l₂ := show to_list (dlist.append l₁ l₂) = to_list l₁ ++ to_list l₂, from by cases l₁; cases l₂; simp; rsimp lemma to_list_cons (x : α) (l : dlist α) : to_list (cons x l) = x :: to_list l := by cases l; rsimp lemma to_list_concat (x : α) (l : dlist α) : to_list (concat x l) = to_list l ++ [x] := by cases l; simp; rsimp section transfer protected def rel_dlist_list (d : dlist α) (l : list α) : Prop := to_list d = l instance bi_total_rel_dlist_list : @relator.bi_total (dlist α) (list α) dlist.rel_dlist_list := ⟨take d, ⟨to_list d, rfl⟩, take l, ⟨of_list l, to_list_of_list l⟩⟩ protected lemma rel_eq : (dlist.rel_dlist_list ⇒ dlist.rel_dlist_list ⇒ iff) (@eq (dlist α)) eq | l₁ ._ rfl l₂ ._ rfl := ⟨congr_arg to_list, suppose to_list l₁ = to_list l₂, have of_list (to_list l₁) = of_list (to_list l₂), from congr_arg of_list this, by simp [of_list_to_list] at this; assumption⟩ protected lemma rel_empty : dlist.rel_dlist_list (@empty α) [] := to_list_empty protected lemma rel_singleton : (@eq α ⇒ dlist.rel_dlist_list) (λx, singleton x) (λx, [x]) | ._ x rfl := to_list_singleton x protected lemma rel_append : (dlist.rel_dlist_list ⇒ dlist.rel_dlist_list ⇒ dlist.rel_dlist_list) (λ(x y : dlist α), x ++ y) (λx y, x ++ y) | l₁ ._ rfl l₂ ._ rfl := to_list_append l₁ l₂ protected lemma rel_cons : (@eq α ⇒ dlist.rel_dlist_list ⇒ dlist.rel_dlist_list) cons (λx y, x :: y) | x ._ rfl l ._ rfl := to_list_cons x l protected lemma rel_concat : (@eq α ⇒ dlist.rel_dlist_list ⇒ dlist.rel_dlist_list) concat (λx y, y ++ [x]) | x ._ rfl l ._ rfl := to_list_concat x l protected meta def transfer : tactic unit := do transfer.transfer [`relator.rel_forall_of_total, `dlist.rel_eq, `dlist.rel_empty, `dlist.rel_singleton, `dlist.rel_append, `dlist.rel_cons, `dlist.rel_concat] example : ∀(a b c : dlist α), a ++ (b ++ c) = (a ++ b) ++ c := begin dlist.transfer, intros, simp end example : ∀(a : α), singleton a ++ empty = singleton a := begin dlist.transfer, intros, simp end end transfer end dlist