# 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.