Skip to content

Commit

Permalink
Write docs and README
Browse files Browse the repository at this point in the history
  • Loading branch information
vrom911 committed Mar 31, 2019
1 parent 3a68456 commit cec6533
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 9 deletions.
52 changes: 51 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,54 @@
[![MPL-2.0 license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](LICENSE)
[![Build status](https://secure.travis-ci.org/vrom911/slist.svg)](https://travis-ci.org/vrom911/slist)

Sized list
This package introduces sized list data type — `Slist`. The data type
has the following shape:

```haskell
data Slist a = Slist
{ sList :: [a]
, sSize :: Size
}
```

As you can see along with the familiar list, it contains `Size` field that
represents the size of the structure. Slists can be finite or infinite, and this
is expressed with `Size`.

```haskell
data Size
= Size Int
| Infinity
```

This representation of the list gives some additional advantages. Getting the
length of the list is the "free" operation (runs in `O(1)`). This property
helps to improve the performance for a bunch of functions like `take`, `drop`,
`at`, etc. But also it doesn't actually add any overhead on the existing
functions.

Also, this allows to write a number of safe functions like `safeReverse`,
`safeHead`, `safeLast`, `safeIsSuffixOf`, etc.

## Comparison

Check out the comparison table between lists and slists performance.

| Function | list (finite) | list (infinite) | Slist (finite) | Slist (infinite) |
|-------------------|-----------------------------------|-----------------------------|----------------------------------------|------------------|
| `length` | `O(n)` | <_hangs_> | `O(1)` | `O(1)` |
| `safeLast` | `O(n)` | <_hangs_> | `O(n)` | `O(1)` |
| `init` | `O(n)` | <_hangs_> | `O(n)` | `O(1)` |
| `take` | `O(min i n)` | `O(i)` | `0 < i < n`: `O(i)`; otherwise: `O(1)` | `O(i)` |
| `at` | `O(min i n)` (run-time exception) | `O(i)` (run-time exception) | `0 < i < n`: `O(i)`; otherwise: `O(1)` | `O(i)` |
| `safeStripPrefix` | `O(m)` | `O(m)` (can hang) | `O(m)` | `O(m)` |

## Potential usage cases

* When you ask the length of the list too frequently.
* When you need to convert to data structures that require to know the list
size in advance for allocating an array of the elements.
_Example:_ [Vector data structure](https://hackage.haskell.org/package/vector).
* When you need to serialised lists.
* When you need to control the behaviour depending on the finiteness of the list.
* When you need a more efficient or safe implementation of some functions.
11 changes: 5 additions & 6 deletions slist.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ cabal-version: 2.0
name: slist
version: 0.0.0
synopsis: Sized list
description: Sized list
description: This package implements @Slist@ data structure that stores the size
of the list along with the list itself.
homepage: https://github.com/vrom911/slist
bug-reports: https://github.com/vrom911/slist/issues
license: MPL-2.0
Expand All @@ -14,7 +15,9 @@ category: Data Structures, List
build-type: Simple
extra-doc-files: README.md
, CHANGELOG.md
tested-with: GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.3
tested-with: GHC == 8.2.2
, GHC == 8.4.4
, GHC == 8.6.3

source-repository head
type: git
Expand All @@ -25,10 +28,8 @@ library
exposed-modules: Slist
Slist.Size


build-depends: base >= 4.10.1.0 && < 4.13


ghc-options: -Wall
-Wincomplete-uni-patterns
-Wincomplete-record-updates
Expand Down Expand Up @@ -60,7 +61,6 @@ test-suite slist-test
build-depends: base >= 4.10.1.0 && < 4.13
, slist


ghc-options: -Wall
-threaded
-rtsopts
Expand Down Expand Up @@ -95,7 +95,6 @@ test-suite slist-doctest
build-depends: base >= 4.9 && < 5
, doctest
, Glob
, QuickCheck

ghc-options: -threaded
default-language: Haskell2010
65 changes: 63 additions & 2 deletions src/Slist.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,68 @@ Copyright: (c) 2019 vrom911
License: MPL-2.0
Maintainer: Veronika Romashkina <vrom911@gmail.com>
This module introduces sized list data type — 'Slist'.
This module introduces sized list data type — 'Slist'. The data type
has the following shape:
@
__data__ 'Slist' a = Slist
{ sList :: [a]
, sSize :: 'Size'
}
@
As you can see along with the familiar list, it contains 'Size' field that
represents the size of the structure. Slists can be finite or infinite, and this
is expressed with 'Size'.
@
__data__ 'Size'
= Size 'Int'
| Infinity
@
This representation of the list gives some additional advantages. Getting the
length of the list is the "free" operation (runs in \( O(1) \)). This property
helps to improve the performance for a bunch of functions like 'take', 'drop',
'at', etc. But also it doesn't actually add any overhead on the existing
functions.
Also, this allows to write a number of safe functions like 'safeReverse',
'safeHead', 'safeLast', 'safeIsSuffixOf', etc.
== Comparison
Check out the comparison table between lists and slists performance.
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
| Function | list (finite) | list (infinite) | Slist (finite) | Slist (infinite) |
+===================+====================+====================+=======================+=======================+
| 'length' | \( O(n) \) | \</hangs/\> | \( O(1) \) | \( O(1) \) |
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
| 'safeLast' | \( O(n) \) | \</hangs/\> | \( O(n) \) | \( O(1) \) |
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
| 'init' | \( O(n) \) | \</hangs/\> | \( O(n) \) | \( O(1) \) |
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
| 'take' | \( O(min\ i\ n) \) | \( O(i) \) | @0 < i < n@: \(O(i)\) | \(O(i)\) |
| | | | otherwise: \(O(1)\) | |
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
| 'at' | \( O(min\ i\ n) \) | \( O(i) \) | @0 < i < n@: \(O(i)\) | \( O(i) \) |
| | run-time exception | run-time exception | otherwise: \(O(1)\) | |
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
| 'safeStripPrefix' | \( O(m) \) | \( O(m) \) | \( O(m) \) | \( O(m) \) |
| | | can hang | | |
+-------------------+--------------------+--------------------+-----------------------+-----------------------+
== Potential usage cases
* When you ask the length of the list too frequently.
* When you need to convert to data structures that require to know the list
size in advance for allocating an array of the elements. /Example:/ [Vector data
structure](https://hackage.haskell.org/package/vector).
* When you need to serialised lists.
* When you need to control the behaviour depending on the finiteness of the list.
* When you need a more efficient or safe implementation of some functions.
-}

module Slist
Expand Down Expand Up @@ -1771,7 +1832,7 @@ sortBy f Slist{..} = Slist (L.sortBy f sList) sSize

{- | @O(n log n)@.
Sorts a list by comparing the results of a key function applied to each
element. @sortOn f@ is equivalent to @'sortBy' ('comparing' f)@, but has the
element. @sortOn f@ is equivalent to @'sortBy' (comparing f)@, but has the
performance advantage of only evaluating @f@ once for each element in the
input list. This is called the decorate-sort-undecorate paradigm, or
Schwartzian transform.
Expand Down

0 comments on commit cec6533

Please sign in to comment.