Utility functions
This module contains functions that extend the functionality of standard data types, other types of utility functionality get their own module
module Util
import Data.SortedSet
import Data.String
import Data.List.Lazy
import Data.List1
import Data.Vect
import Data.Fin
%default total
Foldable
General utility functions for foldables
minBy
||| Get the minimum element of a collection using the provided comparison
||| function and seed value
export
minBy : Foldable f => (cmp : a -> a -> Ordering) -> (acc : a) -> f a -> a
minBy cmp acc x =
foldl
(\acc, e =>
case e `cmp` acc of
LT => e
_ => acc)
acc x
||| Get the maximum element of a collection using the provided comparison
||| function and seed value
export
maxBy : Foldable f => (cmp : a -> a -> Ordering) -> (acc : a) -> f a -> a
maxBy cmp acc x =
foldl
(\acc, e =>
case e `cmp` acc of
GT => e
_ => acc)
acc x
Functions
repeatN
Recursively applies f
to seed
N times
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
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.
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
contains
Returns True
if the list contains the given value
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]]
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
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
permutations
Lazily generate all the permutations of a Vect
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))
minBy and maxBy
||| Get the minimum element of a non-empty vector by using the provided
||| comparison function
export
minBy : (f : a -> a -> Ordering) -> Vect (S n) a -> a
minBy f (x :: xs) = Foldable.minBy f x xs
||| Get the maximum element of a non-empty vector by using the provided
||| comparison function
export
maxBy : (f : a -> a -> Ordering) -> Vect (S n) a -> a
maxBy f (x :: xs) = Foldable.maxBy f x xs
Convert a list to a vect as a sigma type
export
listToVect : List a -> (n : Nat ** Vect n a)
listToVect xs = (length xs ** fromList xs)
Fin
||| 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
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
length
Count the number of elements in a sorted set
export
length : SortedSet k -> Nat
length x = foldl (\acc, e => acc + 1) 0 x
String
Extend Data.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.
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
Lazily take the cartesian product of two foldables
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
export
lazyConcat : LazyList (LazyList a) -> LazyList a
lazyConcat [] = []
lazyConcat (x :: xs) = x ++ lazyConcat xs
Group
Lazily group a LazyList
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
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