Safe Haskell | None |
---|---|
Language | Haskell2010 |
Binary lists are lists whose number of elements is a power of two. This data structure is efficient for some computations like:
- Splitting a list in half.
- Appending two lists of the same length.
- Extracting an element from the list.
All the functions exported are total except for fromListWithDefault
.
It is impossible for the user of this library to create a binary list
whose length is not a power of two.
Since many names in this module clash with the names of some Prelude functions, you probably want to import this module this way:
import Data.BinaryList (BinList) import qualified Data.BinaryList as BL
Remember that binary lists are an instance of the Foldable
and Traversable
classes. If you are missing a function here, look for functions using those
instances.
Note that some functions like replicate
, generate
, or take
, don't use
the length of the list as argument, but the exponent of its length expressed
as a power of two. Throughout this document, this is referred (perhaps improperly)
as the length index. For example, if the list has length 16, its length index
is 4 since 2^4 = 16. Therefore replicate 4 0
will create a list with 16 zeroes.
Keep this in mind when using this library. Note as well that this implies that
there is no need to check that the length argument is or is not a power of two.
- data BinList a
- singleton :: a -> BinList a
- append :: BinList a -> BinList a -> Maybe (BinList a)
- replicate :: Int -> a -> BinList a
- replicateA :: Applicative f => Int -> f a -> f (BinList a)
- replicateAR :: Applicative f => Int -> f a -> f (BinList a)
- generate :: Int -> (Int -> a) -> BinList a
- lengthIndex :: BinList a -> Int
- length :: BinList a -> Int
- lookup :: BinList a -> Int -> Maybe a
- head :: BinList a -> a
- last :: BinList a -> a
- split :: BinList a -> Either a (BinList a, BinList a)
- take :: Int -> BinList a -> BinList a
- takeEnd :: Int -> BinList a -> BinList a
- reverse :: BinList a -> BinList a
- joinPairs :: BinList (a, a) -> BinList a
- disjoinPairs :: BinList a -> Maybe (BinList (a, a))
- zip :: BinList a -> BinList b -> BinList (a, b)
- unzip :: BinList (a, b) -> (BinList a, BinList b)
- zipWith :: (a -> b -> c) -> BinList a -> BinList b -> BinList c
- fromList :: [a] -> Maybe (BinList a)
- fromListWithDefault :: a -> [a] -> BinList a
Type
A binary list is a list containing a power of two elements. Note that a binary list is never empty.
Construction
append :: BinList a -> BinList a -> Maybe (BinList a) Source
O(1). Append two binary lists. This is only possible
if both lists have the same length. If this condition
is not hold, Nothing
is returned.
replicate :: Int -> a -> BinList a Source
O(log n). Calling replicate n x
builds a binary list with
2^n
occurences of x
.
replicateA :: Applicative f => Int -> f a -> f (BinList a) Source
Calling replicateA n f
builds a binary list collecting the results of
executing 2^n
times the applicative action f
.
replicateAR :: Applicative f => Int -> f a -> f (BinList a) Source
The same as replicateA
, but the actions are executed in reversed order.
generate :: Int -> (Int -> a) -> BinList a Source
O(n). Build a binary list with the given length index (see lengthIndex
)
by applying a function to each index.
Queries
lengthIndex :: BinList a -> Int Source
O(1). Given a binary list l
with length 2^k
:
lengthIndex l = k
lookup :: BinList a -> Int -> Maybe a Source
O(log n). Lookup an element in the list by its index (starting from 0).
If the index is out of range, Nothing
is returned.
Deconstruction
split :: BinList a -> Either a (BinList a, BinList a) Source
O(1). Split a binary list into two sublists of half the length, unless the list only contains one element. In that case, it just returns that element.
take :: Int -> BinList a -> BinList a Source
O(log n). Calling take n xs
returns the first min (2^n) (length xs)
elements of xs
.
takeEnd :: Int -> BinList a -> BinList a Source
O(log n). Calling takeEnd n xs
returns the last min (2^n) (length xs)
elements of xs
.
Transformation
Tuples
joinPairs :: BinList (a, a) -> BinList a Source
O(n). Transform a list of pairs into a flat list. The resulting list will have twice more elements than the original.
disjoinPairs :: BinList a -> Maybe (BinList (a, a)) Source
Zipping and Unzipping
zipWith :: (a -> b -> c) -> BinList a -> BinList b -> BinList c Source
O(n). Zip two binary lists using an operator.
Lists
fromList :: [a] -> Maybe (BinList a) Source
O(n). Build a binary list from a linked list. If the input list
has length different from a power of two, it returns Nothing
.
fromListWithDefault :: a -> [a] -> BinList a Source
O(n). Build a binary list from a linked list. If the input list has length different from a power of two, fill to the next power of two with a default element.
Warning: this function crashes if the input list length is larger than any
power of two in the type Int
. However, this is very unlikely.
Example: Radix-2 FFT
This is an example demonstrating the use of binary lists to calculate the Discrete Fourier Transform of complex vectors with the Radix-2 Fast Fourier Transform algorithm.
import Data.BinaryList (BinList) import qualified Data.BinaryList as BL import Data.Complex import Data.Maybe (fromJust) i :: Complex Double i = 0 :+ 1 fft :: BinList (Complex Double) -> BinList (Complex Double) fft xs = case BL.disjoinPairs xs of Nothing -> xs Just ps -> let (evens,odds) = BL.unzip ps n = BL.lengthIndex xs - 1 q = negate $ pi * i / fromIntegral (2^n) twiddles = BL.generate n $ \k -> exp $ q * fromIntegral k oddsfft = BL.zipWith (*) twiddles $ fft odds evensfft = fft evens in fromJust $ BL.append (BL.zipWith (+) evensfft oddsfft) (BL.zipWith (-) evensfft oddsfft)