module Plumbing (
Pipe,
pass, passWhile, passUntil,
skip, skipWhile, skipUntil,
fit,
pfilter,
rest,
stop,
(=+=), (=|=),
splice,
pump
) where
-- | A processor of a list. Consumes some part of the front of the list,
-- returning some processed results (the yield), and the remainder of the list
type Pipe e = [e] -> ([e],[e])
-- | Yields the first n elements of the list.
pass :: Int -> Pipe e
pass = splitAt
-- | Skips the first n elements of the list
skip :: Int -> Pipe e
skip n es = ([], drop n es)
-- | Yields the longest prefix of elements that meet some criteria
passWhile :: (e -> Bool) -> Pipe e
passWhile = span
-- | Skips the longest prefix of elements that meet some criteria
skipWhile :: (e -> Bool) -> Pipe e
skipWhile f es = ([], dropWhile f es)
-- | Inverted versions of passWhile and skipWhile.
passUntil, skipUntil :: (e -> Bool) -> Pipe e
passUntil = passWhile . (not .)
skipUntil = skipWhile . (not .)
-- | Lift any transformation on a list into a Pipe that yields all the
-- elements so transformed.
fit :: ([e] -> [e]) -> Pipe e
fit f es = (f es, [])
-- | Yield all the elements filtered by some criteria.
pfilter :: (e -> Bool) -> Pipe e
pfilter = fit . filter
-- | Yield all the elements.
rest :: Pipe e
rest es = (es,[])
-- | Skip all the elements.
stop :: Pipe e
stop es = ([],[])
-- | Transform some yielded results by some function.
-- Useful for constructing higher order pipe operations.
splice :: ([e] -> [e]) -> ([e],[e]) -> ([e],[e])
splice f (rs,es) = (f rs, es)
-- | Concatenate two pipes. The first pipe processes as much as it wants,
-- then the second pipe is run on what is left. The yields are concatentated.
(=+=) :: Pipe e -> Pipe e -> Pipe e
f =+= g = \es -> let (rs',es') = f es in (rs'++) `splice` g es'
infixl 2 =+=
-- | Process the yield of on pipe through another. The first pipe yields some
-- elements, which are fed into the second pipe. The yield of the second pipe
-- is the final yield. Any elements from the first pipe's yeild that the
-- second pipe doesn't process are discarded.
(=|=) :: Pipe e -> Pipe e -> Pipe e
f =|= g = \es -> pump g `splice` f es
infixl 3 =|=
-- | Apply a pipe to some elements, returning the yield.
pump :: Pipe e -> [e] -> [e]
pump f = fst . f