Indexable: Containers Subsetting and Slicing
This is a Haskell package mainly used for subsetting and slicing all kinds of containers or nested containers that may have different types.
This package defined a typeclass called "indexable", whose main operator is slicing operator (&)
. The folllowing is a small example (in ghci)
import Indexable -- import the package
lst = [0..10] -- create a list
lst&[""] -- select all elements
lst&["0,3,8"] -- select elements of index 0, 3 and 8
lst&["2:"] -- select all elements from index 2 to the end
lst&[":-1"] -- select all elements except the last one
lst&["1:-1:2"] -- select elements in range with step size 2
lst&["1:3,4:6,8"] -- elements 1:3, 4:6 and the 8th.
the outputs in ghci are:
[0,1,2,3,4,5,6,7,8,9,10]
[0,3,8]
[2,3,4,5,6,7,8,9,10]
[0,1,2,3,4,5,6,7,8,9]
[1,3,5,7,9]
[1,2,4,5,8]
One Dimension Slicing
A slicing request is a string with multiple slicing terms connected by separator ",", like
slicing_request1 = "1,3,5" -- has three terms "1", "3" and "5"
slicing_request2 = "1:10:2,11:20,78,90" -- has four terms "1:10:2", "11:20", "78", "90"
Each term is a string represents a list of keys or indexes in numbers.
Index Slicing (for list-like container)
The general version of a term is "a:b:c"
where a
is the starting index, b
is the ending index, c
is the step. The defualt value (when term is ":b:c"
) is 0
, default for b
is the length of the container, default value for c
is 1
.
Like in python, value of b can be negative, in this case it means how many elements you want to dissmiss at the end of the container.
Key Slicing (for map-like container)
Slicing for map-like containers has only one requirement on the type of key, that is readable. Each slicing term is composed in the form
key_slice_term1 = "xxxx[1:10:2]xxxxx"
key_slice_term2 = "xxxx"
i.e. it can be a string represent the key, or a string with "[slicing term]" (not request, just term) inside. You can still connect terms together as a key slicing requrest like below
key_slice_request = "key[0:5], newkey1, oldkey2, other[3:8:2]key"
Multiple Dimension Slicing
Lift Nested Container into Composed Type
The multiple dimensional containers need to be constructed as a composed type. Below is an example of map of lists (in ghci).
import Indexable -- import indexable package
import Data.Map.Strict -- import the map container
import Data.Functor.Compose -- import the compose functor
mlst = [(i,[i..i+3]) | i<-[0..3]] -- an list of tuples with first value as key
-- second as a list of numbers.
mmap = fromList mlst -- construct map of lists, the type is (Map Integer [Integer])
cmap = Compose mmap -- lift nested container to composed type
-- so we can use slicing operator (&) on it
Apply Slicing on Composed Containers
We can slice on any nested container with a list of slicing requests, with the ith request perform on the ith dimension. Continues on the example above:
cmap&[":","0,1"] -- all rows in the map, with first two entries of each list
cmap&["1:3","1:-1"] -- rows (items in the map) 1 and 2, with each list from index 1 to len-1
cmap&["::2"] -- all rows with step 2, and all elements in list of each row
the outputs are:
Compose (fromList [(0,[0,1]),(1,[1,2]),(2,[2,3]),(3,[3,4])])
Compose (fromList [(1,[2,3]),(2,[3,4])])
Compose (fromList [(0,[0,1,2,3]),(2,[2,3,4,5])])
For higher level nested containers, we need to first construct composed type with the corresponding level. For example, the map of lists of vectors, say mlv
, needs to be composed twice, cmlv = Compose $ Compose mlv
before applying (&)
operator.
Current Instances of Indexable
- Data.List
- Data.Map.Strict
- Data.HashMap.Strict
- Data.IntMap
- Data.Sequence
- Data.Vector
and all finite nested combination of above containers.
Create New Instances
To add new containers f
with key b
as indexable, two minimal functions need to be provided:
(&?) :: f a -> b -> Maybe a
: a function safely return the element of type a
by a key of tyep b
.
fromLst :: (Typeable b) => [(b,a)] -> f a
: a function that construct container f
of value a
from a list of key value pairs. (list-like containers should forget the keys in this function).
After appling these two function, new container can be nested with other containers and using slicing operator (&)
.
Other Operators Available in Indexable
(&?)
safe lookup
(&!)
unsafe lookup
How to Install
This package is currently in the candidate package pool of Hackage. You can download from there, or simply clone this git.