Idris2/libs/contrib/Data/List/Alternating.idr
2021-11-10 08:40:25 +00:00

257 lines
6.3 KiB
Idris

module Data.List.Alternating
import Data.Bifoldable
import Data.List
infixl 5 +>
infixr 5 <+
%default total
mutual
namespace Odd
||| Non-empty list, starting and ending with an a, where adjacent elements alternate
||| between types a and b.
||| We can think of this type as:
||| - A fence, with the `a`s as fence-posts, and the `b`s as panels.
||| - A non-empty list of `a`s, separated by `b`s
||| - A list of `b`s, separated by, and surrounded by, `a`s
||| - The free extension of a monoid `a`, with variables in `b`
public export
data Odd a b = (::) a (Even b a)
namespace Even
||| A list, starting with an a, and ending with a b; where adjacent elements
||| alternate between types a and b.
||| Equivalent to List (a, b)
public export
data Even a b = Nil | (::) a (Odd b a)
%name Odd xs, ys, zs
%name Even xs, ys, zs
mutual
public export
Eq a => Eq b => Eq (Odd a b) where
x :: xs == y :: ys = x == y && assert_total (xs == ys)
public export
Eq a => Eq b => Eq (Even a b) where
[] == [] = True
x :: xs == y :: ys = x == y && xs == ys
_ == _ = False
mutual
public export
Ord a => Ord b => Ord (Odd a b) where
compare (x :: xs) (y ::ys)
= case compare x y of
EQ => assert_total (compare xs ys)
c => c
public export
Ord a => Ord b => Ord (Even a b) where
compare [] [] = EQ
compare [] (x :: xs) = LT
compare (x :: xs) [] = GT
compare (x :: xs) (y ::ys)
= case compare x y of
EQ => compare xs ys
c => c
mutual
public export
Bifunctor Odd where
bimap f g (x :: xs) = (f x) :: assert_total (bimap g f xs)
public export
Bifunctor Even where
bimap f g [] = []
bimap f g (x :: xs) = (f x) :: (bimap g f xs)
mutual
public export
Bifoldable Odd where
bifoldr f g acc (x :: xs) = f x (assert_total $ bifoldr g f acc xs)
bifoldl f g acc (x :: xs) = assert_total $ bifoldl g f (f acc x) xs
public export
Bifoldable Even where
bifoldr f g acc [] = acc
bifoldr f g acc (x :: xs) = f x (bifoldr g f acc xs)
bifoldl f g acc [] = acc
bifoldl f g acc (x :: xs) = bifoldl g f (f acc x) xs
mutual
public export
Bitraversable Odd where
bitraverse f g (x :: xs) = [| f x :: assert_total (bitraverse g f xs) |]
public export
Bitraversable Even where
bitraverse f g [] = [| [] |]
bitraverse f g (x :: xs) = [| f x :: bitraverse g f xs |]
namespace Snd
public export
Functor (Odd a) where
map = mapSnd
namespace Fst
public export
[FstFunctor] Functor (\a => Odd a b) where
map = mapFst
mutual
namespace Odd
public export
(++) : Odd a b -> Odd b a -> Even a b
(x :: xs) ++ ys = x :: xs ++ ys
namespace EvenOdd
public export
(++) : Even a b -> Odd a b -> Odd a b
[] ++ ys = ys
(x :: xs) ++ ys = x :: xs ++ ys
mutual
namespace Even
public export
(++) : Even a b -> Even a b -> Even a b
[] ++ ys = ys
(x :: xs) ++ ys = x :: xs ++ ys
namespace OddEven
public export
(++) : Odd a b -> Even b a -> Odd a b
(x :: xs) ++ ys = x :: xs ++ ys
||| The semigroup structure induced by treating Odd as the free extension of a
||| monoid `a`, with variables in `b`
public export
Semigroup a => Semigroup (Odd a b) where
[x] <+> (y :: ys) = (x <+> y) :: ys
(x :: y :: xs) <+> ys = x :: y :: xs <+> ys
namespace Odd
public export
(+>) : Semigroup a => Odd a b -> a -> Odd a b
[x] +> z = [x <+> z]
x :: y :: xs +> z = x :: y :: (xs +> z)
public export
(<+) : Semigroup a => a -> Odd a b -> Odd a b
x <+ y :: ys = (x <+> y) :: ys
public export
Semigroup (Even a b) where
(<+>) = (++)
public export
Monoid a => Monoid (Odd a b) where
neutral = [neutral]
public export
Monoid (Even a b) where
neutral = []
public export
Foldable (Odd a) where
foldr = bifoldr (flip const)
foldl = bifoldl const
public export
singleton : a -> Odd a b
singleton x = [x]
namespace Snd
public export
Monoid a => Applicative (Odd a) where
pure x = [neutral, x, neutral]
fs <*> xs = biconcatMap singleton (flip map xs) fs
public export
flatten : Odd (Odd a b) b -> Odd a b
flatten [x] = x
flatten (x :: y :: xs) = x ++ (y :: flatten xs)
namespace Fst
public export
[FstApplicative] Applicative (\a => Odd a b) using FstFunctor where
pure x = [x]
fs <*> xs = flatten $ bimap (flip mapFst xs) id fs
public export
Monoid a => Alternative (Odd a) where
empty = [neutral]
xs <|> ys = xs <+> ys
namespace Snd
public export
[SndMonad] Monoid a => Monad (Odd a) where
x >>= f = assert_total $ biconcatMap singleton f x
public export
(>>=) : Monoid a => Odd a b -> (b -> Odd a c) -> Odd a c
(>>=) = (>>=) @{SndMonad}
namespace Fst
public export
[FstMonad] Monad (\a => Odd a b) using FstApplicative where
x >>= f = flatten $ mapFst f x
join = flatten
public export
(>>=) : Odd a c -> (a -> Odd b c) -> Odd b c
(>>=) = (>>=) @{FstMonad}
public export
Traversable (Odd a) where
traverse = bitraverse pure
mutual
namespace Odd
public export
odds : Odd a b -> List a
odds (x :: xs) = x :: evens xs
namespace Even
public export
evens : Even a b -> List b
evens [] = []
evens (x :: xs) = odds xs
mutual
namespace Odd
public export
evens : Odd a b -> List b
evens (x :: xs) = odds xs
namespace Even
public export
odds : Even a b -> List a
odds [] = []
odds (x :: xs) = x :: evens xs
mutual
namespace Odd
public export
forget : Odd a a -> List a
forget (x :: xs) = x :: forget xs
namespace Even
public export
forget : Even a a -> List a
forget [] = []
forget (x :: xs) = x :: forget xs
export
Show a => Show b => Show (Odd a b) where
show xs = "[\{concat $ intersperse ", " $ forget $ bimap show show xs}]"
export
Show a => Show b => Show (Even a b) where
show xs = "[\{concat $ intersperse ", " $ forget $ bimap show show xs}]"