Lazy lists #
The type LazyList α
is a lazy list with elements of type α
.
In the VM, these are potentially infinite lists
where all elements after the first are computed on-demand.
(This is only useful for execution in the VM,
logically we can prove that LazyList α
is isomorphic to List α
.)
Lazy list. All elements (except the first) are computed lazily.
The singleton lazy list.
Equations
- LazyList.singleton x = let a := x; LazyList.cons a (Thunk.pure LazyList.nil)
Constructs a lazy list from a list.
Equations
- LazyList.ofList [] = LazyList.nil
- LazyList.ofList (h :: t) = LazyList.cons h { fn := fun (x : Unit) => LazyList.ofList t }
Converts a lazy list to a list. If the lazy list is infinite, then this function does not terminate.
Equations
- LazyList.nil.toList = []
- (LazyList.cons h t).toList = h :: t.get.toList
Returns the first element of the lazy list,
or default
if the lazy list is empty.
Equations
- x.headI = match x with | LazyList.nil => default | LazyList.cons h tl => h
Removes the first element of the lazy list.
Equations
- x.tail = match x with | LazyList.nil => LazyList.nil | LazyList.cons hd t => t.get
Appends two lazy lists.
Equations
- LazyList.nil.append x = x.get
- (LazyList.cons h t).append x = LazyList.cons h { fn := fun (x_1 : Unit) => t.get.append x }
Maps a function over a lazy list.
Equations
- LazyList.map f LazyList.nil = LazyList.nil
- LazyList.map f (LazyList.cons h t) = LazyList.cons (f h) { fn := fun (x : Unit) => LazyList.map f t.get }
Maps a binary function over two lazy list.
Like LazyList.zip
, the result is only as long as the smaller input.
Equations
- LazyList.map₂ f LazyList.nil x = LazyList.nil
- LazyList.map₂ f x LazyList.nil = LazyList.nil
- LazyList.map₂ f (LazyList.cons h₁ t₁) (LazyList.cons h₂ t₂) = LazyList.cons (f h₁ h₂) { fn := fun (x : Unit) => LazyList.map₂ f t₁.get t₂.get }
Zips two lazy lists.
Equations
- LazyList.zip = LazyList.map₂ Prod.mk
The monadic join operation for lazy lists.
Equations
- LazyList.nil.join = LazyList.nil
- (LazyList.cons h t).join = h.append { fn := fun (x : Unit) => t.get.join }
The list containing the first n
elements of a lazy list.
Equations
- LazyList.take 0 x = []
- LazyList.take x LazyList.nil = []
- LazyList.take a.succ (LazyList.cons h t) = h :: LazyList.take a t.get
The lazy list of all elements satisfying the predicate. If the lazy list is infinite and none of the elements satisfy the predicate, then this function will not terminate.
Equations
- LazyList.filter p LazyList.nil = LazyList.nil
- LazyList.filter p (LazyList.cons h t) = if p h then LazyList.cons h { fn := fun (x : Unit) => LazyList.filter p t.get } else LazyList.filter p t.get
The nth element of a lazy list as an option (like List.get?
).
Equations
- LazyList.nil.get? x = none
- (LazyList.cons a tl).get? 0 = some a
- (LazyList.cons hd l).get? n.succ = l.get.get? n
The infinite lazy list [x, f x, f (f x), ...]
of iterates of a function.
This definition is partial because it creates an infinite list.
The infinite lazy list [i, i+1, i+2, ...]
Equations
Equations
- LazyList.nil.decidableEq LazyList.nil = isTrue ⋯
- (LazyList.cons x_2 xs).decidableEq (LazyList.cons y ys) = if h : x_2 = y then match xs.get.decidableEq ys.get with | isFalse h2 => isFalse ⋯ | isTrue h2 => isTrue ⋯ else isFalse ⋯
- LazyList.nil.decidableEq (LazyList.cons hd tl) = isFalse ⋯
- (LazyList.cons hd tl).decidableEq LazyList.nil = isFalse ⋯
Traversal of lazy lists using an applicative effect.
Equations
- LazyList.traverse f LazyList.nil = pure LazyList.nil
- LazyList.traverse f (LazyList.cons h t) = Seq.seq (LazyList.cons <$> f h) fun (x : Unit) => Thunk.pure <$> LazyList.traverse f t.get
init xs
, if xs
non-empty, drops the last element of the list.
Otherwise, return the empty list.
Equations
- LazyList.nil.init = LazyList.nil
- (LazyList.cons h t).init = match t.get with | LazyList.nil => LazyList.nil | LazyList.cons hd tl => LazyList.cons h { fn := fun (x : Unit) => t.get.init }
Return the first object contained in the list that satisfies
predicate p
Equations
- LazyList.find p LazyList.nil = none
- LazyList.find p (LazyList.cons h t) = if p h then some h else LazyList.find p t.get
interleave xs ys
creates a list where elements of xs
and ys
alternate.
Equations
- LazyList.nil.interleave x = x
- (LazyList.cons hd tl).interleave LazyList.nil = LazyList.cons hd tl
- (LazyList.cons x_2 xs).interleave (LazyList.cons y ys) = LazyList.cons x_2 { fn := fun (x : Unit) => LazyList.cons y { fn := fun (x : Unit) => xs.get.interleave ys.get } }
interleaveAll (xs::ys::zs::xss)
creates a list where elements of xs
, ys
and zs
and the rest alternate. Every other element of the resulting list is taken from
xs
, every fourth is taken from ys
, every eighth is taken from zs
and so on.
Equations
- LazyList.interleaveAll [] = LazyList.nil
- LazyList.interleaveAll (x_1 :: xs) = x_1.interleave (LazyList.interleaveAll xs)
Reverse the order of a LazyList
.
It is done by converting to a List
first because reversal involves evaluating all
the list and if the list is all evaluated, List
is a better representation for
it than a series of thunks.
Equations
- xs.reverse = LazyList.ofList xs.toList.reverse
Try applying function f
to every element of a LazyList
and
return the result of the first attempt that succeeds.
Equations
- LazyList.mfirst f LazyList.nil = failure
- LazyList.mfirst f (LazyList.cons h t) = HOrElse.hOrElse (f h) fun (x : Unit) => LazyList.mfirst f t.get
Membership in lazy lists
Equations
- LazyList.Mem x LazyList.nil = False
- LazyList.Mem x (LazyList.cons h t) = (x = h ∨ LazyList.Mem x t.get)
Equations
- LazyList.instMembership = { mem := LazyList.Mem }
Equations
- One or more equations did not get rendered due to their size.
- LazyList.Mem.decidable x LazyList.nil = isFalse ⋯
map for partial functions #
Partial map. If f : ∀ a, p a → β
is a partial function defined on
a : α
satisfying p
, then pmap f l h
is essentially the same as map f l
but is defined only when all members of l
satisfy p
, using the proof
to apply f
.
Equations
- LazyList.pmap f LazyList.nil x_2 = LazyList.nil
- LazyList.pmap f (LazyList.cons x_2 xs) H = LazyList.cons (f x_2 ⋯) { fn := fun (x : Unit) => LazyList.pmap f xs.get ⋯ }
"Attach" the proof that the elements of l
are in l
to produce a new LazyList
with the same elements but in the type {x // x ∈ l}
.
Equations
- l.attach = LazyList.pmap Subtype.mk l ⋯