import Base
import Nat
import Option
import Set
import MultiSet
import Pair
import Maps
union List<T> {
empty
node(T, List<T>)
}
function length<E>(List<E>) -> Nat {
length(empty) = 0
length(node(n, next)) = 1 + length(next)
}
function operator ++ <E>(List<E>, List<E>) -> List<E> {
operator ++([], ys) = ys
operator ++(node(n, xs), ys) = node(n, xs ++ ys)
}
function reverse<E>(List<E>) -> List<E> {
reverse([]) = []
reverse(node(n, next)) = reverse(next) ++ [n]
}
function set_of<T>(List<T>) -> Set<T> {
set_of(empty) = ∅
set_of(node(x, xs)) = single(x) ∪ set_of(xs)
}
function mset_of<T>(List<T>) -> MultiSet<T> {
mset_of(empty) = m_fun(λx{0})
mset_of(node(x, xs)) = m_one(x) ⨄ mset_of(xs)
}
function map<T,U>(List<T>, fn T->U) -> List<U> {
map(empty, f) = empty
map(node(x, ls), f) = node(f(x), map(ls, f))
}
function foldr<T,U>(List<T>, U, fn T,U->U) -> U {
foldr(empty, u, c) = u
foldr(node(t, ls), u, c) = c(t, foldr(ls, u, c))
}
function foldl<T,U>(List<T>, U, fn U,T->U) -> U {
foldl(empty, u, c) = u
foldl(node(t, ls), u, c) = foldl(ls, c(u, t), c)
}
function down_from(Nat) -> List<Nat> {
down_from(zero) = empty
down_from(suc(n)) = node(n, down_from(n))
}
define up_to : fn Nat -> List<Nat> = λ n { reverse(down_from(n)) }
function interval(Nat, Nat) -> List<Nat> {
interval(zero, begin) = empty
interval(suc(num), begin) = node(begin, interval(num, suc(begin)))
}
define range : fn Nat,Nat -> List<Nat> = λ b, e { interval(e - b, b) }
function zip<T,U>(List<T>, List<U>) -> List< Pair<T, U> > {
zip(empty, ys) = empty
zip(node(x, xs'), ys) =
switch ys {
case empty { empty }
case node(y, ys') { node(pair(x,y), zip(xs', ys')) }
}
}
function filter<E>(List<E>, fn (E)->bool) -> List<E> {
filter(empty, P) = empty
filter(node(x, ls), P) =
if P(x) then node(x, filter(ls, P))
else filter(ls, P)
}
function remove<T>(List<T>, T) -> List<T> {
remove(empty, y) = empty
remove(node(x, xs'), y) =
if x = y then
xs'
else
node(x, remove(xs', y))
}
function remove_all<T>(List<T>, T) -> List<T> {
remove_all(empty, y) = empty
remove_all(node(x, xs'), y) =
if x = y then
remove_all(xs', y)
else
node(x, remove_all(xs', y))
}
function get<T>(List<T>, Nat) -> Option<T> {
get(empty, i) = none
get(node(x, xs), i) =
if i = 0 then
just(x)
else
get(xs, pred(i))
}
function take<T>(Nat, List<T>) -> List<T> {
take(0, xs) = empty
take(suc(n), xs) =
switch xs {
case empty { empty }
case node(x, xs') { node(x, take(n, xs')) }
}
}
function drop<T>(Nat, List<T>) -> List<T> {
drop(0, xs) = xs
drop(suc(n), xs) =
switch xs {
case empty { empty }
case node(x, xs') { drop(n, xs') }
}
}
fun head<T>(ls : List<T>) {
switch ls {
case empty { @none<T> }
case node(x, xs) { just(x) }
}
}
fun tail<T>(ls : List<T>) {
switch ls {
case empty { @empty<T> }
case node(x, xs) { xs }
}
}
theorem length_append: all U :type, xs :List<U>, ys :List<U>.
length(xs ++ ys) = length(xs) + length(ys)
proof
arbitrary U :type
induction List<U>
case [] {
arbitrary ys:List<U>
conclude length(@[]<U> ++ ys) = length(@[]<U>) + length(ys) by evaluate
}
case node(n, xs') suppose IH {
arbitrary ys :List<U>
equations
length(node(n,xs') ++ ys)
= 1 + length(xs' ++ ys) by evaluate
... = 1 + (length(xs') + length(ys)) by replace IH[ys]
... = length(node(n,xs')) + length(ys) by evaluate
}
end
theorem length_zero_empty: all T:type, xs:List<T>.
if length(xs) = 0
then xs = empty
proof
arbitrary T:type
arbitrary xs:List<T>
switch xs {
case empty { . }
case node(x, xs') {
suppose len_z
conclude false
by apply not_one_add_zero[length(xs')] to
definition length in len_z
}
}
end
theorem append_assoc: all U :type, xs :List<U>, ys :List<U>, zs:List<U>.
(xs ++ ys) ++ zs = xs ++ (ys ++ zs)
proof
arbitrary U :type
induction List<U>
case empty {
evaluate
}
case node(n, xs') suppose IH {
arbitrary ys :List<U>, zs :List<U>
equations
(node(n,xs') ++ ys) ++ zs
= node(n, (xs' ++ ys) ++ zs) by definition operator++
... = node(n, xs' ++ (ys ++ zs)) by rewrite IH[ys, zs]
... = # node(n,xs') ++ (ys ++ zs) # by definition operator++
}
end
associative operator++ <T> in List<T>
theorem append_empty: all U :type, xs :List<U>.
xs ++ [] = xs
proof
arbitrary U:type
induction List<U>
case empty {
conclude (empty : List<U>) ++ empty = empty by definition operator++
}
case node(n, xs') suppose IH: xs' ++ empty = xs' {
equations
node(n,xs') ++ empty
= node(n, xs' ++ empty) by definition operator++
... = node(n,xs') by rewrite IH
}
end
theorem length_reverse: all U :type, xs :List<U>.
length(reverse(xs)) = length(xs)
proof
arbitrary U : type
induction List<U>
case empty {
conclude length(reverse(@empty<U>)) = length(@empty<U>)
by definition reverse
}
case node(n, xs') suppose IH {
equations
length(reverse(node(n,xs')))
= length(reverse(xs') ++ node(n,empty)) by definition reverse
... = length(reverse(xs')) + length(node(n,empty))
by rewrite length_append<U>[reverse(xs')][node(n,empty)]
... = length(xs') + length(node(n,empty)) by rewrite IH
... = length(xs') + 1 by evaluate
... = 1 + length(xs') by rewrite add_commute
... = # length(node(n,xs')) # by definition length
}
end
lemma reverse_append: all U :type, xs :List<U>, ys :List<U>.
reverse(xs ++ ys) = reverse(ys) ++ reverse(xs)
proof
arbitrary U :type
induction List<U>
case [] {
arbitrary ys :List<U>
equations
reverse(@[]<U> ++ ys)
= reverse(ys) by definition operator++
... = # reverse(ys) ++ [] # by rewrite append_empty<U>[reverse(ys)]
... = # reverse(ys) ++ reverse([]) # by definition reverse
}
case node(n, xs') suppose IH {
arbitrary ys :List<U>
equations
reverse(node(n,xs') ++ ys)
= reverse(node(n, xs' ++ ys)) by definition operator++
... = reverse(xs' ++ ys) ++ [n] by definition reverse
... = (reverse(ys) ++ reverse(xs')) ++ [n] by rewrite IH[ys]
... = reverse(ys) ++ (reverse(xs') ++ [n]) by append_assoc<U>[reverse(ys)][reverse(xs'), [n]]
... = # reverse(ys) ++ reverse(node(n,xs')) # by definition reverse
}
end
theorem length_map: all T:type, f:fn T->T, xs:List<T>.
length(map(xs, f)) = length(xs)
proof
arbitrary T:type
arbitrary f:fn T->T
induction List<T>
case empty {
definition map
}
case node(x, ls') suppose IH {
equations
length(map(node(x,ls'),f))
= 1 + length(map(ls',f)) by definition {map, length}
... = 1 + length(ls') by rewrite IH
... =# length(node(x,ls')) # by definition {length}
}
end
theorem map_id: all T:type, f:fn T->T. if (all x:T. f(x) = x) then
all xs:List<T>. map(xs, f) = xs
proof
arbitrary T:type
arbitrary f:fn T->T
suppose fxx: (all x:T. f(x) = x)
induction List<T>
case empty {
conclude map(@empty<T>, f) = empty by definition map
}
case node(x, ls) suppose IH {
equations
map(node(x,ls),f)
= node(f(x), map(ls, f)) by definition map
... = node(x, map(ls, f)) by rewrite fxx[x]
... = node(x,ls) by rewrite IH
}
end
theorem map_append: all T:type, f: fn T->T, ys:List<T>, xs:List<T>.
map(xs ++ ys, f) = map(xs,f) ++ map(ys, f)
proof
arbitrary T:type
arbitrary f:fn T->T, ys:List<T>
induction List<T>
case empty {
equations
map(@empty<T> ++ ys, f)
= map(ys, f) by definition operator++
... =# @empty<T> ++ map(ys, f) # by definition operator++
... =# map(@empty<T>, f) ++ map(ys, f) # by definition map
}
case node(x, xs')
suppose IH: map(xs' ++ ys, f) = map(xs',f) ++ map(ys, f)
{
equations
map((node(x,xs') ++ ys), f)
= node(f(x), map(xs' ++ ys, f)) by definition operator++ | map
... = node(f(x), map(xs',f) ++ map(ys,f)) by rewrite IH
... = # map(node(x,xs'),f) ++ map(ys,f) # by definition map | operator++
}
end
theorem map_compose: all T:type, U:type, V:type, f:fn T->U, g:fn U->V, ls :List<T>.
map(map(ls, f), g) = map(ls, g ∘ f)
proof
arbitrary T:type, U:type, V:type
arbitrary f:fn T->U, g:fn U->V
induction List<T>
case empty { definition map }
case node(x, ls) suppose IH {
equations
map(map(node(x,ls),f),g)
= node(g(f(x)), map(map(ls, f), g)) by evaluate
... = node(g(f(x)), map(ls, g ∘ f)) by rewrite IH
... = map(node(x,ls), g .o. f) by evaluate
}
end
theorem zip_empty_right: all T:type, U:type, xs:List<T>.
zip(xs, empty : List<U>) = empty
proof
arbitrary T:type, U:type
induction List<T>
case empty { definition zip }
case node(x, xs') { definition zip }
end
theorem zip_map: all T1:type, T2:type, U1:type, U2:type,
f : fn T1 -> T2, g : fn U1 -> U2, xs:List<T1>, ys:List<U1>.
zip(map(xs, f), map(ys, g)) = map(zip(xs,ys), pairfun(f,g))
proof
arbitrary T1:type, T2:type, U1:type, U2:type
arbitrary f:fn T1 -> T2, g:fn U1 -> U2
induction List<T1>
case empty {
arbitrary ys:List<U1>
conclude zip(map(@empty<T1>, f), map(ys,g)) = map(zip(@empty<T1>,ys), pairfun(f,g))
by definition map | zip
}
case node(x, xs') suppose IH {
arbitrary ys:List<U1>
switch ys {
case empty suppose EQ { evaluate }
case node(y, ys') {
equations
zip(map(node(x,xs'),f),map(node(y,ys'),g))
= node(pair(f(x), g(y)), zip(map(xs',f), map(ys',g))) by definition map | zip
... = node(pair(f(x), g(y)), map(zip(xs',ys'), pairfun(f,g))) by rewrite IH[ys']
... = node(pair(f(x), g(y)), map(zip(xs', ys'), λp{pair(f(first(p)), g(second(p)))}))
by definition pairfun
... = map(zip(node(x,xs'),node(y,ys')), pairfun(f,g)) by evaluate
}
}
}
end
theorem set_of_empty: all T:type, xs:List<T>.
if set_of(xs) = ∅
then xs = empty
proof
arbitrary T:type
arbitrary xs:List<T>
switch xs {
case empty {
.
}
case node(x, xs') {
suppose prem
have x_xxs: x ∈ (single(x) ∪ set_of(xs'))
by apply in_left_union<T>[set_of(xs')]
to single_member<T>[x]
conclude false
by apply empty_no_members
to (rewrite (definition set_of in prem) in x_xxs)
}
}
end
theorem set_of_append: all T:type, xs:List<T>, ys:List<T>.
set_of(xs ++ ys) = set_of(xs) ∪ set_of(ys)
proof
arbitrary T:type
induction List<T>
case empty {
arbitrary ys:List<T>
suffices set_of(ys) = ∅ ∪ set_of(ys)
by definition {operator++, set_of}
rewrite empty_union<T>[set_of(ys)]
}
case node(x, xs') suppose IH {
arbitrary ys:List<T>
definition {operator++, set_of}
and rewrite IH[ys]
| union_assoc<T>[single(x), set_of(xs'), set_of(ys)]
}
end
theorem mset_of_empty: all T:type, xs:List<T>.
if mset_of(xs) = m_fun(λx{0})
then xs = empty
proof
arbitrary T:type
arbitrary xs:List<T>
switch xs {
case empty {
.
}
case node(x, xs') {
suppose prem
have cnt_x_z: cnt(m_fun(λx'{0} : fn T->Nat))(x) = 0
by definition cnt
have cnt_x_pos: 1 ≤ cnt(m_fun(λx'{0} : fn T->Nat))(x) by {
suffices 1 ≤ cnt(mset_of(node(x,xs')))(x)
by rewrite symmetric prem
suffices 1 ≤ 1 + cnt(mset_of(xs'))(x)
by evaluate
less_equal_add[1][cnt(mset_of(xs'))(x)]
}
conclude false by {
definition cnt | operator ≤ in
cnt_x_pos
}
}
}
end
theorem som_mset_eq_set: all T:type, xs:List<T>.
set_of_mset(mset_of(xs)) = set_of(xs)
proof
arbitrary T:type
induction List<T>
case empty {
suffices char_fun(λx{(if cnt(m_fun(λx'{0}:fn T->Nat))(x) = 0
then false else true)} : fn T->bool)
= char_fun(λ_{false})
by definition {mset_of, set_of, set_of_mset}
have eq:(λx{if cnt(m_fun(λx'{0} : fn T->Nat))(x) = 0 then false else true}
: fn T->bool)
= λ_{false}
by extensionality arbitrary x:T definition cnt
rewrite eq
}
case node(x, xs') suppose IH {
suffices set_of_mset(m_one(x) ⨄ mset_of(xs')) = single(x) ∪ set_of(xs')
by definition {mset_of, set_of}
suffices single(x) ∪ set_of_mset(mset_of(xs')) = single(x) ∪ set_of(xs')
by rewrite som_union<T>[m_one(x), mset_of(xs')]
| som_one_single<T>[x]
rewrite IH
}
end
theorem not_set_of_remove_all: all W:type, xs:List<W>, y:W.
not (y ∈ set_of(remove_all(xs, y)))
proof
arbitrary U:type
induction List<U>
case empty {
arbitrary y:U
suffices (if y ∈ ∅ then false) by definition {remove_all, set_of}
empty_no_members
}
case node(x, xs')
suppose IH: all y:U. not (y ∈ set_of(remove_all(xs',y)))
{
arbitrary y:U
switch x = y {
case true suppose xy_true {
have x_eq_y: x = y by rewrite xy_true
suffices not (y ∈ set_of(remove_all(node(y,xs'),y)))
by rewrite x_eq_y
suffices not (y ∈ set_of(remove_all(xs',y)))
by definition remove_all
IH[y]
}
case false suppose xy_false {
suffices not (y ∈ set_of(if x = y then remove_all(xs',y)
else node(x,remove_all(xs',y))))
by definition remove_all
suppose y_in_sx_xsy
have y_in_sx_or_xsy: y ∈ single(x) or y ∈ set_of(remove_all(xs',y))
by apply member_union
to (definition set_of in rewrite xy_false in y_in_sx_xsy)
cases y_in_sx_or_xsy
case y_in_sx {
have xy: x = y by apply single_equal<U> to y_in_sx
conclude false by rewrite xy_false in xy
}
case y_in_xsy {
conclude false by apply IH[y] to y_in_xsy
}
}
}
}
end
theorem take_append: all E:type, xs:List<E>, ys:List<E>.
take(length(xs), xs ++ ys) = xs
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary ys:List<E>
definition {length, operator++, take}
}
case node(x, xs') suppose IH {
arbitrary ys:List<E>
definition {length, operator++, operator+, take}
and rewrite zero_add[length(xs')]
| IH[ys]
}
end
theorem length_drop: all E:type, xs:List<E>, n:Nat.
if n ≤ length(xs)
then length(drop(n, xs)) + n = length(xs)
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary n:Nat
assume prem
have: n = 0 by apply zero_le_zero to evaluate in prem
suffices length(drop(0, @[]<E>)) + 0 = length(@[]<E>)
by replace recall n = 0
evaluate
}
case node(x, xs') assume IH: all n:Nat. (if n ≤ length(xs') then length(drop(n, xs')) + n = length(xs')) {
arbitrary n:Nat
assume prem
switch n {
case 0 {
suffices suc(length(xs') + 0) = suc(length(xs')) by evaluate
replace add_zero
}
case suc(n') assume n_sn {
suffices length(drop(n', xs')) + 1 + n' = 1 + length(xs')
by definition length | drop and replace suc_one_add | zero_add
have n_xs: n' ≤ length(xs') by evaluate in replace n_sn in prem
have eq: length(drop(n', xs')) + n' = length(xs') by apply IH[n'] to n_xs
conclude length(drop(n', xs')) + 1 + n' = 1 + length(xs')
by replace (symmetric eq) | add_commute[1, length(drop(n',xs'))]
}
}
}
end
theorem length_drop_zero: all E:type, xs:List<E>, n:Nat.
if length(xs) < n
then length(drop(n, xs)) = 0
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary n:Nat
assume prem
switch n {
case 0 {
conclude length(drop(0, @[]<E>)) = 0
by evaluate
}
case suc(n') {
conclude length(drop(suc(n'), @[]<E>)) = 0
by evaluate
}
}
}
case node(x, xs') assume IH: all n:Nat. (if length(xs') < n then length(drop(n, xs')) = 0) {
arbitrary n:Nat
assume prem
switch n {
case 0 assume nz {
conclude false
by evaluate in replace nz in prem
}
case suc(n') assume n_sn {
suffices length(drop(n', xs')) = 0 by evaluate
have xs_n: length(xs') < n' by {
suffices suc(length(xs')) ≤ n' by definition operator<
definition operator< | length | 2*operator+ | operator≤ in
replace n_sn in prem
}
conclude length(drop(n', xs')) = 0 by apply IH[n'] to xs_n
}
}
}
end
theorem drop_append: all E:type, xs:List<E>, ys:List<E>.
drop(length(xs), xs ++ ys) = ys
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary ys:List<E>
definition {length, operator++, drop}
}
case node(x, xs') suppose IH {
arbitrary ys:List<E>
definition {length, operator++, operator+, drop}
and rewrite zero_add[length(xs')]
| IH[ys]
}
end
theorem get_drop: all T:type, n:Nat, xs:List<T>, i:Nat, d:T.
get(drop(n, xs), i) = get(xs, n + i)
proof
arbitrary T:type
induction Nat
case zero {
arbitrary xs:List<T>, i:Nat, d:T
definition {drop, operator+}
}
case suc(n') suppose IH {
arbitrary xs:List<T>, i:Nat, d:T
switch xs for drop {
case empty {
definition get
}
case node(x, xs') {
have nsz: not (suc(n') + i = 0) by
suppose sz conclude false by definition operator + in sz
suffices get(drop(n', xs'), i) = get(xs', pred(suc(n') + i))
by definition get and rewrite (apply eq_false to nsz)
suffices get(drop(n', xs'), i) = get(xs', n' + i)
by definition {operator +, pred}
IH[xs',i,d]
}
}
}
end
theorem get_append_front: all T:type, xs:List<T>, ys:List<T>, i:Nat.
if i < length(xs)
then get(xs ++ ys, i) = get(xs, i)
proof
arbitrary T:type
induction List<T>
case empty {
arbitrary ys:List<T>, i:Nat
suppose i_z: i < length(@empty<T>)
conclude false by definition {length, operator <, operator ≤} in i_z
}
case node(x, xs) suppose IH {
arbitrary ys:List<T>, i:Nat
suppose i_xxs: i < length(node(x,xs))
switch i {
case zero {
definition {operator++,get}
}
case suc(i') suppose i_si {
suffices get(xs ++ ys, i') = get(xs, i')
by definition {operator++, get, pred}
have i_xs: i' < length(xs) by
apply less_suc_iff_suc_less to
definition {length, operator+, operator+}
in rewrite i_si in i_xxs
apply IH[ys, i'] to i_xs
}
}
}
end
theorem get_append_back: all T:type, xs:List<T>, ys:List<T>, i:Nat.
get(xs ++ ys, length(xs) + i) = get(ys, i)
proof
arbitrary T:type
induction List<T>
case empty {
arbitrary ys:List<T>, i:Nat
definition {operator++, length, operator +}
}
case node(x, xs) suppose IH {
arbitrary ys:List<T>, i:Nat
have X: not ((1 + length(xs)) + i = 0) by {
suppose eq_z
conclude false by evaluate in eq_z
}
suffices get(xs ++ ys, pred((1 + length(xs)) + i)) = get(ys, i)
by definition {operator++,length, get}
and rewrite (apply eq_false to X)
suffices get(xs ++ ys, length(xs) + i) = get(ys, i)
by definition 2*operator + | pred
IH[ys, i]
}
end
theorem get_none: all T:type, xs:List<T>, i:Nat.
if length(xs) <= i
then get(xs, i) = none
proof
arbitrary T:type
induction List<T>
case [] {
arbitrary i:Nat
assume xs_i
conclude get(@[]<T>, i) = none by definition get
}
case node(x, xs) assume IH {
arbitrary i:Nat
assume xxs_i
have i_pos: 1 + length(xs) ≤ i
by definition length in xxs_i
switch i {
case 0 assume iz {
conclude false by definition {operator+,operator+,operator≤} in rewrite iz in i_pos
}
case suc(i') assume isi {
suffices get(xs, i') = none by definition {get,pred}
have xs_i: length(xs) ≤ i' by definition {operator+,operator+,operator≤} in rewrite isi in i_pos
conclude get(xs, i') = none by apply IH to xs_i
}
}
}
end
theorem mset_equal_implies_set_equal: all T:type, xs:List<T>, ys:List<T>.
if mset_of(xs) = mset_of(ys)
then set_of(xs) = set_of(ys)
proof
arbitrary T:type
arbitrary xs:List<T>, ys:List<T>
suppose xs_ys
equations
set_of(xs) = #set_of_mset(mset_of(xs))# by replace som_mset_eq_set<T>[xs]
... = set_of_mset(mset_of(ys)) by replace xs_ys
... = set_of(ys) by som_mset_eq_set<T>[ys]
end
theorem head_append: all E:type, L:List<E>, R:List<E>.
if 0 < length(L)
then head(L ++ R) = head(L)
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary R:List<E>
suppose pos_len
conclude false by definition {length, operator <, operator ≤} in pos_len
}
case node(x, xs) suppose IH {
arbitrary R:List<E>
suppose pos_len
equations
head(node(x,xs) ++ R)
= just(x) by definition {operator++,head}
... =# head(node(x,xs)) # by definition head
}
end
theorem tail_append: all E:type, L:List<E>, R:List<E>.
if 0 < length(L)
then tail(L ++ R) = tail(L) ++ R
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary R:List<E>
suppose pos_len
conclude false
by definition {length, operator <, operator≤} in pos_len
}
case node(x, xs') suppose IH {
arbitrary R:List<E>
suppose pos_len
definition {operator++,tail}
}
end