mirror of
https://github.com/idris-lang/Idris2.git
synced 2024-12-27 13:43:28 +03:00
290 lines
7.0 KiB
Idris
290 lines
7.0 KiB
Idris
module Data.List.Lazy
|
|
|
|
import Data.Fuel
|
|
import Data.Stream
|
|
import Data.Colist
|
|
import Data.Colist1
|
|
|
|
%default total
|
|
|
|
-- All functions here are public export
|
|
-- because their definitions are pretty much the specification.
|
|
|
|
public export
|
|
data LazyList : Type -> Type where
|
|
Nil : LazyList a
|
|
(::) : (x : a) -> (xs : Lazy (LazyList a)) -> LazyList a
|
|
|
|
--- Truly lazy functions ---
|
|
|
|
public export
|
|
foldrLazy : (func : elem -> Lazy acc -> acc) -> (init : Lazy acc) -> (input : LazyList elem) -> acc
|
|
foldrLazy _ init [] = init
|
|
foldrLazy op init (x::xs) = x `op` foldrLazy op init xs
|
|
|
|
public export
|
|
(++) : LazyList a -> Lazy (LazyList a) -> LazyList a
|
|
(++) = flip $ foldrLazy (::)
|
|
|
|
-- Specialized variant of `concatMap` with both `t` and `m` being `LazyList`.
|
|
public export
|
|
bindLazy : (a -> LazyList b) -> LazyList a -> LazyList b
|
|
bindLazy f = foldrLazy ((++) . f) []
|
|
|
|
public export
|
|
choice : Alternative f => LazyList (f a) -> f a
|
|
choice = foldrLazy (<|>) empty
|
|
|
|
public export
|
|
choiceMap : Alternative f => (a -> f b) -> LazyList a -> f b
|
|
choiceMap g = foldrLazy ((<|>) . g) empty
|
|
|
|
public export
|
|
any : (a -> Bool) -> LazyList a -> Bool
|
|
any p = foldrLazy ((||) . p) False
|
|
|
|
public export
|
|
all : (a -> Bool) -> LazyList a -> Bool
|
|
all p = foldrLazy ((&&) . p) True
|
|
|
|
--- Interface implementations ---
|
|
|
|
public export
|
|
Eq a => Eq (LazyList a) where
|
|
[] == [] = True
|
|
x :: xs == y :: ys = x == y && xs == ys
|
|
_ == _ = False
|
|
|
|
public export
|
|
Ord a => Ord (LazyList a) 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
|
|
|
|
export
|
|
Show a => Show (LazyList a) where
|
|
show [] = "[]"
|
|
show (h :: t) = "[" ++ show' "" h t ++ "]"
|
|
where
|
|
-- Idris didn't like the lazyness involved when using the
|
|
-- same implementation as for `List`, therefore, this was
|
|
-- adjusted to first force the head and tail of the list.
|
|
show' : String -> a -> LazyList a -> String
|
|
show' acc h Nil = acc ++ show h
|
|
show' acc h (x :: xs) = show' (acc ++ show h ++ ", ") x xs
|
|
|
|
public export
|
|
Semigroup (LazyList a) where
|
|
xs <+> ys = xs ++ ys
|
|
|
|
public export
|
|
Monoid (LazyList a) where
|
|
neutral = []
|
|
|
|
public export
|
|
Foldable LazyList where
|
|
foldr op nil [] = nil
|
|
foldr op nil (x :: xs) = x `op` foldr op nil xs
|
|
|
|
foldl op acc [] = acc
|
|
foldl op acc (x :: xs) = foldl op (acc `op` x) xs
|
|
|
|
foldlM fm init xs = foldrLazy (\x, k, z => fm z x >>= k) pure xs init
|
|
|
|
null [] = True
|
|
null (_::_) = False
|
|
|
|
foldMap f [] = neutral
|
|
foldMap f (x :: xs) = f x <+> foldMap f xs
|
|
|
|
public export
|
|
Functor LazyList where
|
|
map f [] = []
|
|
map f (x :: xs) = f x :: map f xs
|
|
|
|
public export
|
|
Applicative LazyList where
|
|
pure x = [x]
|
|
fs <*> vs = bindLazy (\f => map f vs) fs
|
|
|
|
public export
|
|
Alternative LazyList where
|
|
empty = []
|
|
(<|>) = (++)
|
|
|
|
public export
|
|
Monad LazyList where
|
|
m >>= f = bindLazy f m
|
|
|
|
-- There is no Traversable instance for lazy lists.
|
|
-- The result of a traversal will be a non-lazy list in general
|
|
-- (you can't delay the "effect" of an applicative functor).
|
|
public export
|
|
traverse : Applicative f => (a -> f b) -> LazyList a -> f (List b)
|
|
traverse g [] = pure []
|
|
traverse g (x :: xs) = [| g x :: traverse g xs |]
|
|
|
|
public export %inline
|
|
for : Applicative f => LazyList a -> (a -> f b) -> f (List b)
|
|
for = flip traverse
|
|
|
|
public export %inline
|
|
sequence : Applicative f => LazyList (f a) -> f (List a)
|
|
sequence = traverse id
|
|
|
|
-- Traverse a lazy list with lazy effect lazily
|
|
public export
|
|
traverse_ : Monad m => (a -> m b) -> LazyList a -> m Unit
|
|
traverse_ f = foldrLazy ((>>) . ignore . f) (pure ())
|
|
|
|
public export %inline
|
|
for_ : Monad m => LazyList a -> (a -> m b) -> m Unit
|
|
for_ = flip Lazy.traverse_
|
|
|
|
public export %inline
|
|
sequence_ : Monad m => LazyList (m a) -> m Unit
|
|
sequence_ = Lazy.traverse_ id
|
|
|
|
public export
|
|
Zippable LazyList where
|
|
zipWith _ [] _ = []
|
|
zipWith _ _ [] = []
|
|
zipWith f (x::xs) (y::ys) = f x y :: zipWith f xs ys
|
|
|
|
zipWith3 _ [] _ _ = []
|
|
zipWith3 _ _ [] _ = []
|
|
zipWith3 _ _ _ [] = []
|
|
zipWith3 f (x::xs) (y::ys) (z::zs) = f x y z :: zipWith3 f xs ys zs
|
|
|
|
unzip xs = (fst <$> xs, snd <$> xs)
|
|
unzipWith = unzip .: map
|
|
|
|
unzip3 xs = (fst <$> xs, fst . snd <$> xs, snd . snd <$> xs)
|
|
unzipWith3 = unzip3 .: map
|
|
|
|
--- Lists creation ---
|
|
|
|
public export
|
|
fromList : List a -> LazyList a
|
|
fromList [] = []
|
|
fromList (x::xs) = x :: fromList xs
|
|
|
|
covering
|
|
public export
|
|
iterate : (f : a -> Maybe a) -> (x : a) -> LazyList a
|
|
iterate f x = x :: case f x of
|
|
Nothing => []
|
|
Just y => iterate f y
|
|
|
|
covering
|
|
public export
|
|
unfoldr : (b -> Maybe (a, b)) -> b -> LazyList a
|
|
unfoldr f c = case f c of
|
|
Nothing => []
|
|
Just (a, n) => a :: unfoldr f n
|
|
|
|
public export
|
|
iterateN : Nat -> (a -> a) -> a -> LazyList a
|
|
iterateN Z _ _ = []
|
|
iterateN (S n) f x = x :: iterateN n f (f x)
|
|
|
|
public export
|
|
replicate : (n : Nat) -> (x : a) -> LazyList a
|
|
replicate Z _ = []
|
|
replicate (S n) x = x :: replicate n x
|
|
|
|
--- Functions acquiring parts of list ---
|
|
|
|
public export
|
|
head' : LazyList a -> Maybe a
|
|
head' [] = Nothing
|
|
head' (x::_) = Just x
|
|
|
|
public export
|
|
tail' : LazyList a -> Maybe (LazyList a)
|
|
tail' [] = Nothing
|
|
tail' (_::xs) = Just xs
|
|
|
|
--- Functions for acquiring different types of sublists ---
|
|
|
|
public export
|
|
take : Nat -> LazyList a -> LazyList a
|
|
take (S k) (x::xs) = x :: take k xs
|
|
take _ _ = []
|
|
|
|
public export
|
|
drop : Nat -> LazyList a -> LazyList a
|
|
drop Z xs = xs
|
|
drop (S _) [] = []
|
|
drop (S n) (_::xs) = drop n xs
|
|
|
|
public export
|
|
takeWhile : (a -> Bool) -> LazyList a -> LazyList a
|
|
takeWhile p [] = []
|
|
takeWhile p (x::xs) = if p x then x :: takeWhile p xs else []
|
|
|
|
public export
|
|
dropWhile : (a -> Bool) -> LazyList a -> LazyList a
|
|
dropWhile p [] = []
|
|
dropWhile p (x::xs) = if p x then dropWhile p xs else x::xs
|
|
|
|
public export
|
|
filter : (a -> Bool) -> LazyList a -> LazyList a
|
|
filter p [] = []
|
|
filter p (x::xs) = if p x then x :: filter p xs else filter p xs
|
|
|
|
public export
|
|
mapMaybe : (a -> Maybe b) -> LazyList a -> LazyList b
|
|
mapMaybe f [] = []
|
|
mapMaybe f (x::xs) = case f x of
|
|
Nothing => mapMaybe f xs
|
|
Just y => y :: mapMaybe f xs
|
|
|
|
namespace Stream
|
|
|
|
public export
|
|
take : Fuel -> Stream a -> LazyList a
|
|
take Dry _ = []
|
|
take (More f) (x :: xs) = x :: take f xs
|
|
|
|
namespace Colist
|
|
|
|
public export
|
|
take : Fuel -> Colist a -> LazyList a
|
|
take Dry _ = []
|
|
take _ [] = []
|
|
take (More f) (x :: xs) = x :: take f xs
|
|
|
|
namespace Colist1
|
|
|
|
public export
|
|
take : Fuel -> Colist1 a -> LazyList a
|
|
take fuel as = take fuel (forget as)
|
|
|
|
--- Functions for extending lists ---
|
|
|
|
public export
|
|
mergeReplicate : a -> LazyList a -> LazyList a
|
|
mergeReplicate sep [] = []
|
|
mergeReplicate sep (y::ys) = sep :: y :: mergeReplicate sep ys
|
|
|
|
public export
|
|
intersperse : a -> LazyList a -> LazyList a
|
|
intersperse sep [] = []
|
|
intersperse sep (x::xs) = x :: mergeReplicate sep xs
|
|
|
|
public export
|
|
intercalate : (sep : LazyList a) -> (xss : LazyList (LazyList a)) -> LazyList a
|
|
intercalate sep xss = choice $ intersperse sep xss
|
|
|
|
--- Functions converting lazy lists to something ---
|
|
|
|
public export
|
|
toColist : LazyList a -> Colist a
|
|
toColist [] = []
|
|
toColist (x::xs) = x :: toColist xs
|