Source

haskell-playground / Plumbing.hs

Full commit
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