extra-data-yj-0.1.0.0: src/Data/List/Infinite.hs
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
module Data.List.Infinite (
-- * Definition
Infinite(..), NonEmpty(..),
-- * Basic functions
append, uncons, concat,
-- * List transformations
intersperse, intercalate, subsequences,
-- * Reducing lists (folds)
foldr,
-- * Scans
scanl, scanl',
-- * Infinite lists
iterate, iterate', repeat, cycle, unfoldr,
-- * Extracting sublits
take, drop, splitAt, span, group, groupBy, inits,
-- * Predicates
isPrefixOf,
-- * Searching
partition,
-- * Indexing lists
index,
-- * Zipping and unzipping lists
zipWith, unzip,
-- * "Set" operations
delete, (\\),
-- * Ordered lists
insert, insertBy
) where
import Prelude hiding (
cycle, (++), concat, scanl, iterate, repeat,
span, take, drop, splitAt, zipWith, unzip )
import Control.Arrow (first, second, (***))
import Data.List.NonEmpty (NonEmpty(..))
-- DEFINITION
infixr 5 :~
data Infinite a = a :~ Infinite a
instance Functor Infinite where f `fmap` (x :~ xs) = f x :~ (f <$> xs)
instance Applicative Infinite where
pure x = x :~ pure x
(f :~ fs) <*> (x :~ xs) = f x :~ (fs <*> xs)
instance Foldable Infinite where
foldr op v (x :~ xs) = x `op` foldr op v xs
-- BASIC FUNCTIONS
append :: [a] -> Infinite a -> Infinite a
[] `append` ys = ys
(x : xs) `append` ys = x :~ (xs `append` ys)
uncons :: Infinite a -> (a, Infinite a)
uncons (x :~ xs) = (x, xs)
concat :: Infinite [a] -> Infinite a
concat ([] :~ xss) = concat xss
concat ((x : xs) :~ xss) = x :~ concat (xs :~ xss)
-- LIST TRANSFORMATIONS
intersperse :: a -> Infinite a -> Infinite a
intersperse x (y :~ ys) = y :~ x :~ intersperse x ys
intercalate :: [a] -> Infinite [a] -> Infinite a
intercalate xs (ys :~ yss) = ys `append` (xs `append` intercalate xs yss)
subsequences, nonEmptySubsequences :: Infinite a -> Infinite [a]
subsequences xs = [] :~ nonEmptySubsequences xs
nonEmptySubsequences (x :~ xs) =
[x] :~ concat ((\ys -> [ys, x : ys]) <$> nonEmptySubsequences xs)
-- REDUCING LISTS (FOLDS)
-- SCANS
scanl, scanl' :: (b -> a -> b) -> b -> Infinite a -> Infinite b
scanl op z (x :~ xs) = z :~ scanl op (z `op` x) xs
scanl' op z (x :~ xs) = z `seq` z :~ scanl' op (z `op` x) xs
-- INFINITE LISTS
iterate, iterate' :: (a -> a) -> a -> Infinite a
iterate f x = x :~ iterate f (f x)
iterate' f x = x `seq` x :~ iterate f (f x)
repeat :: a -> Infinite a
repeat x = x :~ repeat x
cycle :: NonEmpty a -> Infinite a
cycle xs = ccl xs where
ccl (y :| ys) = y :~ case ys of
[] -> cycle xs
(z : zs) -> ccl (z :| zs)
unfoldr :: (b -> (a, b)) -> b -> Infinite a
unfoldr f s = x :~ unfoldr f s' where (x, s') = f s
-- SUBLISTS
take :: Integral i => i -> Infinite a -> [a]
take n = fst . splitAt n
drop :: Integral i => i -> Infinite a -> Infinite a
drop n = snd . splitAt n
splitAt :: Integral i => i -> Infinite a -> ([a], Infinite a)
splitAt n xs | n < 1 = ([], xs)
splitAt n (x :~ xs) = (x :) `first` splitAt (n - 1) xs
span :: (a -> Bool) -> Infinite a -> ([a], Infinite a)
span p xa@(x :~ xs)
| p x = (x :) `first` span p xs
| otherwise = ([], xa)
group :: Eq a => Infinite a -> Infinite [a]
group = groupBy (==)
groupBy :: (a -> a -> Bool) -> Infinite a -> Infinite [a]
groupBy eq (x :~ xs) = (x : ys) :~ groupBy eq zs
where (ys, zs) = span (x `eq`) xs
inits :: Infinite a -> Infinite [a]
inits (x :~ xs) = [] :~ ((x :) <$> inits xs)
-- PREDICATES
isPrefixOf :: Eq a => [a] -> Infinite a -> Bool
isPrefixOf [] _ = True
isPrefixOf (x : xs) (y :~ ys) = x == y && isPrefixOf xs ys
-- SEARCHING LISTS
partition :: (a -> Bool) -> Infinite a -> (Infinite a, Infinite a)
partition p (x :~ xs)
| p x = (x :~) `first` partition p xs
| otherwise = (x :~) `second` partition p xs
-- INDEXING LISTS
infixl 9 `index`
index :: Integral i => Infinite a -> i -> a
_ `index` n | n < 0 = error "negative index"
(x :~ _) `index` 0 = x
(_ :~ xs) `index` n = xs `index` (n - 1)
-- ZIPPING AND UNZIPPING LISTS
zipWith :: (a -> b -> c) -> Infinite a -> Infinite b -> Infinite c
zipWith op (x :~ xs) (y :~ ys) = (x `op` y) :~ zipWith op xs ys
unzip :: Infinite (a, b) -> (Infinite a, Infinite b)
unzip ((x, y) :~ xys) = (x :~) *** (y :~) $ unzip xys
-- SET OPERATIONS
delete :: Eq a => a -> Infinite a -> Infinite a
delete x (y :~ ys)
| x == y = ys
| otherwise = y :~ delete x ys
(\\) :: Eq a => Infinite a -> [a] -> Infinite a
(\\) = foldl $ flip delete
-- ORDERED LISTS
insert :: Ord a => a -> Infinite a -> Infinite a
insert = insertBy compare
insertBy :: (a -> a -> Ordering) -> a -> Infinite a -> Infinite a
insertBy cmp x ya@(y :~ ys) = case cmp x y of
GT -> y :~ insertBy cmp x ys
_ -> x :~ ya