import Base
import ./lib.bend as N
# When from_list succeeds on a Cons, the payload is that Cons as NE.
law from_list_cons:
for -a: Quant
for -A: Kind(a)
for h: A
for t: List
{ N.NonEmpty.from_list(a, A, h <> t) == Some{N.NE{h, t}} : Maybe> }
# from_list on Nil is None.
law from_list_nil:
for -a: Quant
for -A: Kind(a)
{ N.NonEmpty.from_list(a, A, Nil{}) == None{} : Maybe> }
# to_list undoes the NE encoding: recovers head <> tail.
law to_list_ne:
for -a: Quant
for -A: Kind(a)
for h: A
for t: List
{ N.NonEmpty.to_list(a, A, N.NE{h, t}) == h <> t : List }
# to_list(one(x)) is the singleton list.
law to_list_one:
for -a: Quant
for -A: Kind(a)
for x: A
{ N.NonEmpty.to_list(a, A, N.NonEmpty.one(a, A, x)) == x <> Nil{} : List }
# from_list ∘ to_list recovers Some{NE{h,t}}.
law from_to_list_ne:
for -a: Quant
for -A: Kind(a)
for h: A
for t: List
{
N.NonEmpty.from_list(a, A, N.NonEmpty.to_list(a, A, N.NE{h, t}))
== Some{N.NE{h, t}}
: Maybe>
}
# length(NE{h,t}) is always Succ of List.length(t) (hence ≥ 1).
law length_succ_tail:
for -a: Quant
for -A: Kind(a)
for h: A
for t: List
{ N.NonEmpty.length(a, A, N.NE{h, t}) == 1n+List.length(a, A, t) : Nat }
# length(one(x)) is 1.
law length_one:
for -a: Quant
for -A: Kind(a)
for x: A
{ N.NonEmpty.length(a, A, N.NonEmpty.one(a, A, x)) == 1n : Nat }
# head(one(x)) is x.
law head_one:
for -a: Quant
for -A: Kind(a)
for x: A
{ N.NonEmpty.head(a, A, N.NonEmpty.one(a, A, x)) == x : A }
# head/tail project the NE constructor.
law head_ne:
for -a: Quant
for -A: Kind(a)
for h: A
for t: List
{ N.NonEmpty.head(a, A, N.NE{h, t}) == h : A }
law tail_ne:
for -a: Quant
for -A: Kind(a)
for h: A
for t: List
{ N.NonEmpty.tail(a, A, N.NE{h, t}) == t : List }
# tail(one(x)) is Nil.
law tail_one:
for -a: Quant
for -A: Kind(a)
for x: A
{ N.NonEmpty.tail(a, A, N.NonEmpty.one(a, A, x)) == Nil{} : List }
# one(x) is NE{x, Nil}.
law one_is_ne:
for -a: Quant
for -A: Kind(a)
for x: A
{ N.NonEmpty.one(a, A, x) == N.NE{x, Nil{}} : N.NonEmpty }
# cons(x, one(y)) prepends x.
law cons_one:
for -a: Quant
for -A: Kind(a)
for x: A
for y: A
{ N.NonEmpty.cons(a, A, x, N.NonEmpty.one(a, A, y)) == N.NE{x, y <> Nil{}} : N.NonEmpty }
# head(cons(x, one(y))) is x.
law head_cons_one:
for -a: Quant
for -A: Kind(a)
for x: A
for y: A
{ N.NonEmpty.head(a, A, N.NonEmpty.cons(a, A, x, N.NonEmpty.one(a, A, y))) == x : A }
# to_list(cons(x, one(y))) is x <> y <> Nil.
law to_list_cons_one:
for -a: Quant
for -A: Kind(a)
for x: A
for y: A
{
N.NonEmpty.to_list(a, A, N.NonEmpty.cons(a, A, x, N.NonEmpty.one(a, A, y)))
== x <> (y <> Nil{})
: List
}
# snoc(one(x), y) appends y.
law snoc_one:
for -a: Quant
for -A: Kind(a)
for x: A
for y: A
{ N.NonEmpty.snoc(a, A, N.NonEmpty.one(a, A, x), y) == N.NE{x, y <> Nil{}} : N.NonEmpty }
# length(snoc(one(x), y)) is 2.
law length_snoc_one:
for -a: Quant
for -A: Kind(a)
for x: A
for y: A
{ N.NonEmpty.length(a, A, N.NonEmpty.snoc(a, A, N.NonEmpty.one(a, A, x), y)) == 2n : Nat }
# append(one(x), one(y)) is NE{x, y <> Nil}.
law append_ones:
for -a: Quant
for -A: Kind(a)
for x: A
for y: A
{
N.NonEmpty.append(a, A, N.NonEmpty.one(a, A, x), N.NonEmpty.one(a, A, y))
== N.NE{x, y <> Nil{}}
: N.NonEmpty
}