import Base
import UInt
import Option
import Set
import MultiSet
import Pair
import Maps
union List<T> {
empty
node(T, List<T>)
}
recursive length<E>(List<E>) -> UInt {
length(empty) = 0
length(node(n, next)) = 1 + length(next)
}
recursive contains<E>(List<E>, E) -> bool {
contains(empty, x) = false
contains(node(y, next), x) = (y = x) or contains(next, x)
}
recursive operator ++ <E>(List<E>, List<E>) -> List<E> {
operator ++([], ys) = ys
operator ++(node(n, xs), ys) = node(n, xs ++ ys)
}
recursive reverse<E>(List<E>) -> List<E> {
reverse([]) = []
reverse(node(n, next)) = reverse(next) ++ [n]
}
recursive set_of<T>(List<T>) -> Set<T> {
set_of(empty) = ∅
set_of(node(x, xs)) = single(x) ∪ set_of(xs)
}
recursive mset_of<T>(List<T>) -> MultiSet<T> {
mset_of(empty) = m_empty()
mset_of(node(x, xs)) = m_one(x) ⨄ mset_of(xs)
}
recursive 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))
}
recursive 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))
}
recursive 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)
}
recursive 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')) }
}
}
recursive unzip<T,U>(List< Pair<T, U> >) -> Pair< List<T>, List<U> > {
unzip(empty) = pair(@empty<T>, @empty<U>)
unzip(node(p, ps)) =
define xys = unzip(ps);
pair(node(first(p), first(xys)), node(second(p), second(xys)))
}
recursive 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)
}
recursive 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))
}
recursive 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))
}
recursive get<T>(List<T>, UInt) -> Option<T> {
get(empty, i) = none
get(node(x, xs), i) =
if i = 0 then
just(x)
else
get(xs, i ∸ 1)
}
recursive take<T>(List<T>, UInt) -> List<T> {
take(empty, n) = empty
take(node(x, xs), n) =
if n = 0 then empty
else node(x, take(xs, n ∸ 1))
}
recursive drop<T>(List<T>, UInt) -> List<T> {
drop(empty, n) = empty
drop(node(x, xs'), n) =
if n = 0 then node(x, xs')
else drop(xs', n ∸ 1)
}
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 {
expand operator++ | length.
}
}
case node(n, xs') suppose IH {
arbitrary ys :List<U>
equations
length(node(n,xs') ++ ys)
= 1 + length(xs' ++ ys) by expand operator++ | length.
... = 1 + (length(xs') + length(ys)) by replace IH[ys].
... = #length(node(n,xs'))# + length(ys) by expand length.
}
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 uint_not_one_add_zero[length(xs')] to
expand 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 {
expand operator++.
}
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 expand operator++.
... = node(n, xs' ++ (ys ++ zs)) by replace IH[ys, zs].
... = # node(n,xs') ++ (ys ++ zs) # by expand 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 expand operator++.
}
case node(n, xs') suppose IH: xs' ++ empty = xs' {
equations
node(n,xs') ++ empty
= node(n, xs' ++ empty) by expand operator++.
... = node(n,xs') by replace 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 expand reverse.
}
case node(n, xs') suppose IH {
equations
length(reverse(node(n,xs')))
= length(reverse(xs') ++ node(n,empty)) by expand reverse.
... = length(reverse(xs')) + length(node(n,empty))
by replace length_append<U>[reverse(xs')][node(n,empty)].
... = length(xs') + length(node(n,empty)) by replace IH.
... = length(xs') + 1 by expand 2*length.
... = 1 + length(xs') by uint_add_commute
... = # length(node(n,xs')) # by expand 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 expand operator++.
... = # reverse(ys) ++ [] # by replace append_empty<U>[reverse(ys)].
... = # reverse(ys) ++ reverse([]) # by expand reverse.
}
case node(n, xs') suppose IH {
arbitrary ys :List<U>
equations
reverse(node(n,xs') ++ ys)
= reverse(node(n, xs' ++ ys)) by expand operator++.
... = reverse(xs' ++ ys) ++ [n] by expand reverse.
... = (reverse(ys) ++ reverse(xs')) ++ [n] by replace IH[ys].
... = reverse(ys) ++ (reverse(xs') ++ [n]) by append_assoc<U>[reverse(ys)][reverse(xs'), [n]]
... = # reverse(ys) ++ reverse(node(n,xs')) # by expand 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 {
expand map.
}
case node(x, ls') suppose IH {
equations
length(map(node(x,ls'),f))
= 1 + length(map(ls',f)) by expand map | length.
... = 1 + length(ls') by replace IH.
... =# length(node(x,ls')) # by expand 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 expand map.
}
case node(x, ls) suppose IH {
equations
map(node(x,ls),f)
= node(f(x), map(ls, f)) by expand map.
... = node(x, map(ls, f)) by replace fxx[x].
... = node(x,ls) by replace 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 expand operator++.
... =# @empty<T> ++ map(ys, f) # by expand operator++.
... =# map(@empty<T>, f) ++ map(ys, f) # by expand 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 expand operator++ | map.
... = node(f(x), map(xs',f) ++ map(ys,f)) by replace IH.
... = # map(node(x,xs'),f) ++ map(ys,f) # by expand 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 { expand 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 expand map.
... = node(#g ∘ f#(x), map(map(ls, f), g)) by expand operator ∘.
... = node((g ∘ f)(x), map(ls, g ∘ f)) by replace IH.
... = #map(node(x,ls), g .o. f)# by expand map.
}
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 { evaluate }
case node(x, xs') { evaluate }
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 expand 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 expand map | zip.
... = node(pair(f(x), g(y)), map(zip(xs',ys'), pairfun(f,g))) by replace IH[ys'].
... = node(pair(f(x), g(y)), map(zip(xs', ys'), λp{pair(f(first(p)), g(second(p)))}))
by expand 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]
}
have prem2: single(x) ∪ set_of(xs') = ∅ by expand set_of in prem
conclude false by prem2
}
}
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>
expand operator++ | set_of.
}
case node(x, xs') suppose IH {
arbitrary ys:List<T>
expand operator++ | set_of
replace IH[ys].
}
end
theorem mset_of_empty: all T:type, xs:List<T>.
if mset_of(xs) = @m_empty<T>()
then xs = empty
proof
arbitrary T:type
arbitrary xs:List<T>
switch xs {
case empty {
.
}
case node(x, xs') {
suppose prem
have X1: cnt(m_one(x) ⨄ mset_of(xs'))(x) = cnt(@m_empty<T>())(x)
by replace (expand mset_of in prem).
have X2: 1 + cnt(mset_of(xs'))(x) = 0
by replace cnt_sum in X1
conclude false by apply uint_not_one_add_zero to X2
}
}
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 {
expand mset_of | set_of
replace som_empty<T>.
}
case node(x, xs') suppose IH {
suffices set_of_mset(m_one(x) ⨄ mset_of(xs')) = single(x) ∪ set_of(xs')
by expand mset_of | set_of.
suffices single(x) ∪ set_of_mset(mset_of(xs')) = single(x) ∪ set_of(xs')
by replace som_union<T>[m_one(x), mset_of(xs')]
| som_one_single<T>[x].
replace 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
expand remove_all | set_of.
}
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 replace xy_true.
suffices not (y ∈ set_of(remove_all(node(y,xs'),y)))
by replace x_eq_y.
suffices not (y ∈ set_of(remove_all(xs',y)))
by expand 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 expand 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 expand set_of in replace xy_false in y_in_sx_xsy
cases y_in_sx_or_xsy
case y_in_sx {
have xy: x = y by y_in_sx
conclude false by replace xy_false in xy
}
case y_in_xsy {
conclude false by apply IH[y] to y_in_xsy
}
}
}
}
end
theorem take_zero: all E:type, xs:List<E>.
take(xs, 0) = []
proof
arbitrary E:type, xs:List<E>
switch xs {
case empty {
expand take.
}
case node(x, xs') {
expand take.
}
}
end
theorem take_append: all E:type, xs:List<E>, ys:List<E>.
take(xs ++ ys, length(xs)) = xs
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary ys:List<E>
expand operator++ | length
replace take_zero.
}
case node(x, xs') assume IH {
arbitrary ys:List<E>
expand operator++ | take | length
replace IH[ys].
}
end
theorem length_drop: all E:type, xs:List<E>, n:UInt.
if n ≤ length(xs)
then length(drop(xs, n)) + n = length(xs)
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary n:UInt
assume prem
suffices n = 0 by expand drop | length.
apply uint_zero_le_zero[n] to expand length in prem
}
case node(x, xs') assume IH: all n:UInt. (if n ≤ length(xs') then length(drop(xs', n)) + n = length(xs')) {
arbitrary n:UInt
assume prem
cases uint_zero_or_add_one[n]
case nz {
replace nz
evaluate
}
case n1 {
obtain n' where n_sn from n1
replace n_sn
suffices length(drop(xs', n')) + 1 + n' = 1 + length(xs') by {
expand length | drop.
}
have n_xs: n' ≤ length(xs') by {
apply uint_add_both_sides_of_less_equal[1, n', length(xs')] to
expand length in replace n_sn in prem
}
have eq: length(drop(xs', n')) + n' = length(xs')
by apply IH[n'] to n_xs
conclude length(drop(xs', n')) + 1 + n' = 1 + length(xs') by {
replace (symmetric eq)
replace uint_add_commute[length(drop(xs', n')), 1].
}
}
}
end
postulate len_drop: all E:type, xs:List<E>, n:UInt.
if n ≤ length(xs)
then length(drop(xs, n)) + n = length(xs)
theorem length_drop_zero: all E:type, xs:List<E>, n:UInt.
if length(xs) < n
then length(drop(xs, n)) = 0
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary n:UInt
assume prem
evaluate
}
case node(x, xs') assume IH: all n:UInt. (if length(xs') < n then length(drop(xs', n)) = 0) {
arbitrary n:UInt
assume prem
cases uint_zero_or_add_one[n]
case nz {
conclude false by {
apply uint_not_less_zero
to expand length in replace nz in prem
}
}
case n1 {
obtain n' where n_sn from n1
replace n_sn
expand drop
have xs_n: length(xs') < n' by {
apply uint_add_both_sides_of_less[1, length(xs'), n'] to
expand length in replace n_sn in prem
}
conclude length(drop(xs', n')) = 0 by apply IH[n'] to xs_n
}
}
end
theorem drop_zero_identity: all E:type, xs:List<E>.
drop(xs, 0) = xs
proof
arbitrary E:type
induction List<E>
case empty {
expand drop.
}
case node(x, xs') suppose IH {
expand drop.
}
end
theorem drop_append: all E:type, xs:List<E>, ys:List<E>.
drop(xs ++ ys, length(xs)) = ys
proof
arbitrary E:type
induction List<E>
case empty {
arbitrary ys:List<E>
expand operator++ | length
drop_zero_identity
}
case node(x, xs') suppose IH {
arbitrary ys:List<E>
expand length | operator++ | drop
IH[ys]
}
end
theorem get_drop: all T:type, xs:List<T>, n:UInt, i:UInt, d:T.
get(drop(xs, n), i) = get(xs, n + i)
proof
arbitrary T:type
induction List<T>
case empty {
arbitrary n:UInt, i:UInt, d:T
evaluate
}
case node(x, xs') suppose IH {
arbitrary n:UInt, i:UInt, d:T
expand drop
cases uint_zero_or_add_one[n]
case nz {
replace nz.
}
case n1 {
obtain n' where n_sn from n1
replace n_sn
expand get
IH
}
}
end
theorem get_append_front: all T:type, xs:List<T>, ys:List<T>, i:UInt.
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:UInt
suppose i_z: i < length(@empty<T>)
conclude false by {
apply uint_not_less_zero to
expand length in i_z
}
}
case node(x, xs) suppose IH {
arbitrary ys:List<T>, i:UInt
suppose i_xxs: i < length(node(x,xs))
cases uint_zero_or_add_one[i]
case iz {
replace iz
expand operator++ | get.
}
case i1 {
obtain i' where i_si from i1
replace i_si
expand operator++ | get
have i_xs: i' < length(xs) by {
apply uint_add_both_sides_of_less[1, i', length(xs)] to
replace i_si in expand length 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:UInt.
get(xs ++ ys, length(xs) + i) = get(ys, i)
proof
arbitrary T:type
induction List<T>
case empty {
arbitrary ys:List<T>, i:UInt
expand operator++ | length.
}
case node(x, xs) suppose IH {
arbitrary ys:List<T>, i:UInt
expand operator++ | length | get
IH[ys, i]
}
end
theorem get_none: all T:type, xs:List<T>, i:UInt.
if length(xs) <= i
then get(xs, i) = none
proof
arbitrary T:type
induction List<T>
case [] {
arbitrary i:UInt
assume xs_i
conclude get(@[]<T>, i) = none by expand get.
}
case node(x, xs) assume IH {
arbitrary i:UInt
assume xxs_i
have i_pos: 1 + length(xs) ≤ i
by expand length in xxs_i
cases uint_zero_or_add_one[i]
case iz {
replace iz
conclude false by {
apply uint_not_one_add_le_zero to
expand length in replace iz in xxs_i
}
}
case i1 {
obtain i' where i_si from i1
replace i_si
have xs_i: length(xs) ≤ i' by {
apply uint_add_both_sides_of_less_equal[1, length(xs), i'] to
replace i_si in i_pos
}
expand get
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 {
expand length 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 expand operator++ | head.
... =# head(node(x,xs)) # by expand 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 {
expand length in pos_len
}
}
case node(x, xs') suppose IH {
arbitrary R:List<E>
suppose pos_len
expand operator++ | tail.
}
end