# Utility functions

This module contains functions that extend the functionality of standard data
types, other types of utility functionality get their own module

```idris
module Util

import Data.SortedSet
import Data.String
import Data.List.Lazy
import Data.List1
import Data.Vect
import Data.Fin

%default total
```

## Functions

### repeatN

Recursively applies `f` to `seed` N times

```idris
export
repeatN : (times : Nat) -> (f : a -> a) -> (seed : a) -> a
repeatN 0 f seed = seed
repeatN (S times') f seed = repeatN times' f (f seed)
```

## Either

```idris hide
namespace Either
```

### mapLeft

Applies a function to the contents of a `Left` if the value of the given
`Either` is actually a `Left`, otherwise, leaves `Right`s untouched.

```idris
  export
  mapLeft : (f : a -> b) -> Either a c -> Either b c
  mapLeft f (Left x) = Left (f x)
  mapLeft f (Right x) = Right x
```

## List

```idris hide
namespace List
```

### contains

Returns `True` if the list contains the given value

```idris
  export
  contains : Eq a => a -> List a -> Bool
  contains x [] = False
  contains x (y :: xs) = 
    if x == y 
      then True
      else contains x xs
```

### rotations

Provides all the 'rotations' of a list.

Example:

```
rotations [1, 2, 3] == [[1, 2, 3], [3, 1, 2], [2, 3, 1]]
```

```idris
  export
  rotations : List a -> List (List a) 
  rotations xs = rotations' (length xs) xs []
    where
      rotations' : Nat -> List a -> (acc : List (List a)) -> List (List a)
      rotations' 0 xs acc = acc
      rotations' (S k) [] acc = acc
      rotations' (S k) (x :: xs) acc = 
        let next = xs ++ [x]
        in rotations' k next (next :: acc)
```

### permutations

Lazily generate all of the permutations of a list

```idris
  export
  permutations : List a -> LazyList (List a)
  permutations [] = pure []
  permutations xs = do
    (head, tail) <- select xs
    tail <- permutations (assert_smaller xs tail)
    pure $ head :: tail
    where 
      consSnd : a -> (a, List a) -> (a, List a)
      consSnd x (y, xs) = (y, x :: xs)
      select : List a -> LazyList (a, List a)
      select [] = []
      select (x :: xs) = (x, xs) :: map (consSnd x) (select xs)
```

## Vect

```idris hide
namespace Vect
```

### permutations

Lazily generate all the permutations of a Vect

```idris
  export
  permutations : Vect n a -> LazyList (Vect n a)
  permutations [] = []
  permutations [x] = [[x]]
  permutations (x :: xs) = do
    (head, tail) <- select (x :: xs)
    tail <- permutations tail
    pure $ head :: tail
    where
      consSnd : a -> (a, Vect m a) -> (a, Vect (S m) a)
      consSnd x (y, xs) = (y, x :: xs)
      select : Vect (S m) a -> LazyList (a, Vect m a)
      select [y] = [(y, [])]
      select (y :: (z :: ys)) = 
        (y, z :: ys) :: map (consSnd y) (select (z :: ys))
```

## Fin

```idris hide
namespace Fin
```


```idris
  ||| Decriment a Fin, wrapping on overflow
  export
  unfinS : {n : _} -> Fin n -> Fin n
  unfinS FZ = last
  unfinS (FS x) = weaken x
```

## Vectors

Define some operations for pairs of numbers, treating them roughly like vectors

### Addition and Subtraction

```idris hide
export infixl 8 >+<
export infixl 8 >-<

namespace Pair
```

```idris
  public export
  (>+<) : Num a => (x, y : (a, a)) -> (a, a)
  (x_1, x_2) >+< (y_1, y_2) = (x_1 + y_1, x_2 + y_2)

  public export
  (>-<) : Neg a => (x, y : (a, a)) -> (a, a)
  (x_1, x_2) >-< (y_1, y_2) = (x_1 - y_1, x_2 - y_2)
```

## Set

Extend `Data.SortedSet`

```idris hide
namespace Set
```

### length

Count the number of elements in a sorted set

```idris
  export
  length : SortedSet k -> Nat
  length x = foldl (\acc, e => acc + 1) 0 x
```

## String

Extend `Data.String`

```idris hide
namespace String
```

### isSubstr

Returns `True` if `needle` is a substring of `haystack`

We first check to see if the needle is a prefix of the top level haystack,
before calling into a tail recursive helper function that peels one character
off of the string at a time, checking if the needle is a prefix at each step.

```idris
  export
  isSubstr : (needle, haystack : String) -> Bool
  isSubstr needle haystack = 
    if needle `isPrefixOf` haystack 
      then True
      else isSubstr' haystack
    where
    isSubstr' : String -> Bool
    isSubstr' str with (asList str)
      isSubstr' "" | [] = False
      isSubstr' (strCons c str) | (c :: x) = 
        if needle `isPrefixOf` str
          then True
          else isSubstr' str | x
```

## Lazy List

### Cartesian product

```idris hide
namespace LazyList
```

Lazily take the cartesian product of two foldables

```idris
  export
  cartProd : Foldable a => Foldable b => a e -> b f -> LazyList (e, f)
  cartProd x y = 
    let y = foldToLazy y
    in foldr (\e, acc => combine e y acc) [] x
    where
      foldToLazy : Foldable a' => a' e' -> LazyList e'
      foldToLazy x = foldr (\e, acc => e :: acc) [] x
      combine : e -> LazyList f -> LazyList (e, f) -> LazyList (e, f)
      combine x [] rest = rest
      combine x (y :: ys) rest = (x, y) :: combine x ys rest
```

### Concat

Lazily concatenate a LazyList of LazyLists

```idris
  export
  lazyConcat : LazyList (LazyList a) -> LazyList a
  lazyConcat [] = []
  lazyConcat (x :: xs) = x ++ lazyConcat xs
```

### Group

Lazily group a LazyList

```idris
  export
  lazyGroup : Eq a => LazyList a -> LazyList (List1 a)
  lazyGroup [] = []
  lazyGroup (x :: xs) = lazyGroup' xs x (x ::: [])
    where
      lazyGroup' : LazyList a -> (current : a) -> (acc : List1 a)
        -> LazyList (List1 a)
      lazyGroup' [] current acc = [acc]
      lazyGroup' (y :: ys) current acc@(head ::: tail) = 
        if y == current
          then lazyGroup' ys current (head ::: (y :: tail))
          else acc :: lazyGroup (y :: ys)
```

### length

Calculate the length of a LazyList

```idris
  export
  length : LazyList a -> Nat
  length = length' 0
    where
      length' : Nat -> LazyList a -> Nat
      length' k [] = k
      length' k (x :: xs) = length' (S k) xs
```