packages feed

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