include "ListInternal.aes" namespace List = function is_empty(l : list('a)) : bool = switch(l) [] => true _ => false function first(l : list('a)) : option('a) = switch(l) [] => None h::_ => Some(h) function tail(l : list('a)) : option(list('a)) = switch(l) [] => None _::t => Some(t) function last(l : list('a)) : option('a) = switch(l) [] => None [x] => Some(x) _::t => last(t) function drop_last(l : list('a)) : option(list('a)) = switch(l) [] => None _ => Some(drop_last_unsafe(l)) function drop_last_unsafe(l : list('a)) : list('a) = switch(l) [_] => [] h::t => h::drop_last_unsafe(t) [] => abort("drop_last_unsafe: list empty") function contains(e : 'a, l : list('a)) = switch(l) [] => false h::t => h == e || contains(e, t) /** Finds first element of `l` fulfilling predicate `p` as `Some` or `None` * if no such element exists. */ function find(p : 'a => bool, l : list('a)) : option('a) = switch(l) [] => None h::t => if(p(h)) Some(h) else find(p, t) /** Returns list of all indices of elements from `l` that fulfill the predicate `p`. */ function find_indices(p : 'a => bool, l : list('a)) : list(int) = find_indices_(p, l, 0) private function find_indices_( p : 'a => bool , l : list('a) , n : int ) : list(int) = switch(l) [] => [] h::t => let rest = find_indices_(p, t, n+1) if(p(h)) n::rest else rest function nth(n : int, l : list('a)) : option('a) = switch(l) [] => None h::t => if(n == 0) Some(h) else nth(n-1, t) /* Unsafe version of `nth` */ function get(n : int, l : list('a)) : 'a = switch(l) [] => abort(if(n < 0) "Negative index get" else "Out of index get") h::t => if(n == 0) h else get(n-1, t) function length(l : list('a)) : int = length_(l, 0) private function length_(l : list('a), acc : int) : int = switch(l) [] => acc _::t => length_(t, acc + 1) /** Creates an ascending sequence of all integer numbers * between `a` and `b` (including `a` and `b`) */ function from_to(a : int, b : int) : list(int) = [a..b] /** Creates an ascending sequence of integer numbers betweeen * `a` and `b` jumping by given `step`. Includes `a` and takes * `b` only if `(b - a) mod step == 0`. `step` should be bigger than 0. */ function from_to_step(a : int, b : int, s : int) : list(int) = require(step > 0, "List.from_to_step: non-positive step") from_to_step_(a, b - (b-a) mod s, s, []) private function from_to_step_(a : int, b : int, s : int, acc : list(int)) : list(int) = if(b < a) acc else from_to_step_(a, b - s, s, b::acc) /** Unsafe. Replaces `n`th element of `l` with `e`. Crashes on over/underflow */ function replace_at(n : int, e : 'a, l : list('a)) : list('a) = if(n<0) abort("insert_at underflow") else replace_at_(n, e, l) private function replace_at_(n : int, e : 'a, l : list('a)) : list('a) = switch(l) [] => abort("replace_at overflow") h::t => if (n == 0) e::t else h::replace_at_(n-1, e, t) /** Unsafe. Adds `e` to `l` to be its `n`th element. Crashes on over/underflow */ function insert_at(n : int, e : 'a, l : list('a)) : list('a) = if(n<0) abort("insert_at underflow") else insert_at_(n, e, l) private function insert_at_(n : int, e : 'a, l : list('a)) : list('a) = if (n == 0) e::l else switch(l) [] => abort("insert_at overflow") h::t => h::insert_at_(n-1, e, t) /** Assuming that cmp represents `<` comparison, inserts `x` before * the first element in the list `l` which is greater than it */ function insert_by(cmp : (('a, 'a) => bool), x : 'a, l : list('a)) : list('a) = switch(l) [] => [x] h::t => if(cmp(x, h)) // x < h x::l else h::insert_by(cmp, x, t) function foldr(cons : ('a, 'b) => 'b, nil : 'b, l : list('a)) : 'b = switch(l) [] => nil h::t => cons(h, foldr(cons, nil, t)) function foldl(rcons : ('b, 'a) => 'b, acc : 'b, l : list('a)) : 'b = switch(l) [] => acc h::t => foldl(rcons, rcons(acc, h), t) function foreach(l : list('a), f : 'a => unit) : unit = switch(l) [] => () e::l' => f(e) foreach(l', f) function reverse(l : list('a)) : list('a) = reverse_(l, []) private function reverse_(l : list('a), acc : list('a)) : list('a) = switch(l) [] => acc h::t => reverse_(t, h::acc) function map(f : 'a => 'b, l : list('a)) : list('b) = switch(l) [] => [] h::t => f(h)::map(f, t) /** Effectively composition of `map` and `flatten` */ function flat_map(f : 'a => list('b), l : list('a)) : list('b) = ListInternal.flat_map(f, l) function filter(p : 'a => bool, l : list('a)) : list('a) = switch(l) [] => [] h::t => let rest = filter(p, t) if(p(h)) h::rest else rest /** Take up to `n` first elements */ function take(n : int, l : list('a)) : list('a) = if(n < 0) abort("Take negative number of elements") else take_(n, l) private function take_(n : int, l : list('a)) : list('a) = if(n == 0) [] else switch(l) [] => [] h::t => h::take_(n-1, t) /** Drop up to `n` first elements */ function drop(n : int, l : list('a)) : list('a) = if(n < 0) abort("Drop negative number of elements") else drop_(n, l) private function drop_(n : int, l : list('a)) : list('a) = if (n == 0) l else switch(l) [] => [] h::t => drop_(n-1, t) /** Get the longest prefix of a list in which every element * matches predicate `p` */ function take_while(p : 'a => bool, l : list('a)) : list('a) = switch(l) [] => [] h::t => if(p(h)) h::take_while(p, t) else [] /** Drop elements from `l` until `p` holds */ function drop_while(p : 'a => bool, l : list('a)) : list('a) = switch(l) [] => [] h::t => if(p(h)) drop_while(p, t) else l /** Splits list into two lists of elements that respectively * match and don't match predicate `p` */ function partition(p : 'a => bool, l : list('a)) : (list('a) * list('a)) = switch(l) [] => ([], []) h::t => let (l, r) = partition(p, t) if(p(h)) (h::l, r) else (l, h::r) function flatten(l : list(list('a))) : list('a) = switch(l) [] => [] h::t => h ++ flatten(t) function all(p : 'a => bool, l : list('a)) : bool = switch(l) [] => true h::t => if(p(h)) all(p, t) else false function any(p : 'a => bool, l : list('a)) : bool = switch(l) [] => false h::t => if(p(h)) true else any(p, t) function sum(l : list(int)) : int = switch(l) [] => 0 h::t => h + sum(t) function product(l : list(int)) : int = switch(l) [] => 1 h::t => h * sum(t) /** Zips two list by applying bimapping function on respective elements. * Drops the tail of the longer list. */ private function zip_with( f : ('a, 'b) => 'c , l1 : list('a) , l2 : list('b) ) : list('c) = switch ((l1, l2)) (h1::t1, h2::t2) => f(h1, h2)::zip_with(f, t1, t2) _ => [] /** Zips two lists into list of pairs. * Drops the tail of the longer list. */ function zip(l1 : list('a), l2 : list('b)) : list('a * 'b) = zip_with((a, b) => (a, b), l1, l2) function unzip(l : list('a * 'b)) : (list('a) * list('b)) = switch(l) [] => ([], []) (h1, h2)::t => let (t1, t2) = unzip(t) (h1::t1, h2::t2) /** Merges two sorted lists using `lt` comparator */ function merge : (('a, 'a) => bool, list('a), list('a)) => list('a) merge(lt, x::xs, y::ys) = if(lt(x, y)) x::merge(lt, xs, y::ys) else y::merge(lt, x::xs, ys) merge(_, [], ys) = ys merge(_, xs, []) = xs /** Mergesort inspired by * https://hackage.haskell.org/package/base-4.14.1.0/docs/src/Data.OldList.html#sort */ function sort : (('a, 'a) => bool, list('a)) => list('a) sort(_, []) = [] sort(lt, l) = merge_all(lt, monotonic_subs(lt, l)) /** Splits list into compound increasing sublists */ private function monotonic_subs : (('a, 'a) => bool, list('a)) => list(list('a)) monotonic_subs(lt, x::y::rest) = if(lt(y, x)) desc(lt, y, [x], rest) else asc(lt, y, [x], rest) monotonic_subs(_, l) = [l] /** Extracts the longest descending prefix and proceeds with monotonic split */ private function desc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a)) desc(lt, x, acc, h::t) = if(lt(x, h)) (x::acc) :: monotonic_subs(lt, h::t) else desc(lt, h, x::acc, t) desc(_, x, acc, []) = [x::acc] /** Extracts the longest ascending prefix and proceeds with monotonic split */ private function asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a)) asc(lt, x, acc, h::t) = if(lt(h, x)) List.reverse(x::acc) :: monotonic_subs(lt, h::t) else asc(lt, h, x::acc, t) asc(_, x, acc, []) = [List.reverse(x::acc)] /** Merges list of sorted lists */ private function merge_all : (('a, 'a) => bool, list(list('a))) => list('a) merge_all(_, [part]) = part merge_all(lt, parts) = merge_all(lt, merge_pairs(lt, parts)) /** Single round of `merge_all` – pairs of lists in a list of list */ private function merge_pairs : (('a, 'a) => bool, list(list('a))) => list(list('a)) merge_pairs(lt, x::y::rest) = merge(lt, x, y) :: merge_pairs(lt, rest) merge_pairs(_, l) = l /** Puts `delim` between every two members of the list */ function intersperse(delim : 'a, l : list('a)) : list('a) = switch(l) [] => [] [e] => [e] h::t => h::delim::intersperse(delim, t) /** Effectively a zip with an infinite sequence of natural numbers */ function enumerate(l : list('a)) : list(int * 'a) = enumerate_(l, 0) private function enumerate_(l : list('a), n : int) : list(int * 'a) = switch(l) [] => [] h::t => (n, h)::enumerate_(t, n + 1)