Copyright | © 2017-2020 Oleg Grenrus 2020 Sean Leather |
---|---|
License | BSD-3-Clause |
Maintainer | sean.leather@gmail.com |
Stability | stable |
Safe Haskell | Safe |
Language | Haskell2010 |
A
non-empty difference list
is a difference list paired with a
head
element. Like the difference list, it supports
\(\mathcal{O}\)
(
1
)
append
and
snoc
operations.
This module provides the type for a non-empty difference list,
DNonEmpty
, and
a collection of supporting functions for (a) converting to and from
NonEmpty
and
DList
and (b) operating efficiently on
DNonEmpty
values. The functions
also retain the non-strict semantics of
NonEmpty
.
Synopsis
- data DNonEmpty a = a :| ( DList a)
- fromNonEmpty :: NonEmpty a -> DNonEmpty a
- toNonEmpty :: DNonEmpty a -> NonEmpty a
- toList :: DNonEmpty a -> [a]
- fromList :: [a] -> DNonEmpty a
- singleton :: a -> DNonEmpty a
- cons :: a -> DNonEmpty a -> DNonEmpty a
- snoc :: DNonEmpty a -> a -> DNonEmpty a
- append :: DNonEmpty a -> DNonEmpty a -> DNonEmpty a
- head :: DNonEmpty a -> a
- tail :: DNonEmpty a -> DList a
- unfoldr :: (b -> (a, Maybe b)) -> b -> DNonEmpty a
- map :: (a -> b) -> DNonEmpty a -> DNonEmpty b
Non-Empty Difference List Type
A non-empty difference list is a pair of a
head
element and a (possibly empty)
difference list.
Just as
DList
is a representation of a list, so is
DNonEmpty
a
representation of a
NonEmpty
.
DNonEmpty
supports
\(\mathcal{O}\)
(
1
)
append
and
snoc
operations, making it useful for replacing frequent
applications of
<>
on
NonEmpty
(which is implemented with
++
),
especially if those uses are left-nested (e.g.
(a
).
<>
b)
<>
c
Unlike
DList
,
DNonEmpty
is not an abstract type: its constructor is
exported. An alternative definition of
DNonEmpty
is:
newtype DNonEmpty a = DNonEmpty ([a] -> NonEmpty
a)
This type would need to be abstract to avoid producing
DNonEmpty
values that
are not isomorphic to
NonEmpty
values. However, this type would also require
some functions (such as
map
) to be implemented with
fromNonEmpty
(and thus
++
), which could introduce efficiencies.
Instances
Conversion
fromNonEmpty :: NonEmpty a -> DNonEmpty a Source #
fromNonEmpty xs
is a
DNonEmpty
representing the
NonEmpty
xs
.
fromNonEmpty
obeys the laws:
toNonEmpty
. fromNonEmpty =id
fromNonEmpty .toNonEmpty
=id
As with
fromList
, this function is implemented with
++
. Repeated uses
of
fromNonEmpty
are just as inefficient as repeated uses of
++
. If you find
yourself doing some form of the following (possibly indirectly), you may not be
taking advantage of the
DNonEmpty
representation and library:
fromNonEmpty . f . toNonEmpty
More likely, you will convert from a
NonEmpty
, perform some operation on the
DNonEmpty
, and convert back to a
NonEmpty
:
toNonEmpty
. g . fromNonEmpty
toNonEmpty :: DNonEmpty a -> NonEmpty a Source #
toNonEmpty xs
is the
NonEmpty
represented by
xs
.
toNonEmpty
obeys the laws:
toNonEmpty .fromNonEmpty
=id
fromNonEmpty
. toNonEmpty =id
As with
toList
, evaluating
toNonEmpty xs
may “collapse” the chain of
function composition underlying many
DList
functions (
append
in
particular) used to construct the
tail
of
xs
. This may affect any efficiency
you achieved due to laziness in the construction.
toList :: DNonEmpty a -> [a] Source #
toList xs
is the non-empty list represented by
xs
.
toList
obeys the law:
toList xs =toList
(toNonEmpty
xs)
fromList :: [a] -> DNonEmpty a Source #
fromList xs
is a
DNonEmpty
representing the list
xs
. If
xs
is
empty, an
error
is raised.
fromList
obeys the law:
fromList xs =fromNonEmpty
(fromList
xs)
Basic Functions
singleton :: a -> DNonEmpty a Source #
singleton x
is a
DNonEmpty
with the single element
x
.
singleton
obeys the law:
toNonEmpty
(singleton x) = x:|
[]
cons :: a -> DNonEmpty a -> DNonEmpty a infixr 9 Source #
cons x xs
is a
DNonEmpty
with the
head
x
and the
tail
xs
.
\(\mathcal{O}\)
(
1
).
cons
obeys the law:
toNonEmpty
(cons x xs) =cons
x (toNonEmpty
xs)
snoc :: DNonEmpty a -> a -> DNonEmpty a infixl 9 Source #
snoc xs x
is a
DNonEmpty
with the initial
DNonEmpty
xs
and the
last element
x
.
\(\mathcal{O}\)
(
1
).
snoc
obeys the law:
toNonEmpty
(snoc xs x) =toNonEmpty
xs<>
(x:|
[])
append :: DNonEmpty a -> DNonEmpty a -> DNonEmpty a Source #
append xs ys
is a
DNonEmpty
obtained from the concatenation of the
elements of
xs
and
ys
.
\(\mathcal{O}\)
(
1
).
append
obeys the law:
toNonEmpty
(append xs ys) =toNonEmpty
xs<>
toNonEmpty
ys
head :: DNonEmpty a -> a Source #
head xs
is the first element of
xs
.
\(\mathcal{O}\)
(
1
).
head
obeys the law:
head xs =head
(toNonEmpty
xs)
tail :: DNonEmpty a -> DList a Source #
tail xs
is a
DList
of the elements in
xs
excluding the first
element.
\(\mathcal{O}\)
(
1
).
tail
obeys the law:
toList
(tail xs) =tail
(toNonEmpty
xs)
map :: (a -> b) -> DNonEmpty a -> DNonEmpty b Source #
map f xs
is the
DNonEmpty
obtained by applying
f
to each element
of
xs
.
\(\mathcal{O}\)
(
).
length
(
toNonEmpty
xs)
map
obeys the law:
toNonEmpty
(map f xs) =map
f (toNonEmpty
xs)