    {-# LANGUAGE FlexibleContexts #-}

    {-
    Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>

    All rights reserved.

    For license and copyright information, see the file COPYRIGHT

    -}

    {- |
       Module     : Data.ListLike.Utils
       Copyright  : Copyright (C) 2007 John Goerzen
       License    : BSD3

       Maintainer : David Fox <dsf@seereason.com>, Andreas Abel
       Stability  : stable
       Portability: portable

    Utilities for 'Data.ListLike.ListLike' and friends.  More functions
    similar to 'Data.List' but not part of the main typeclass.

    Written by John Goerzen, jgoerzen\@complete.org
    -}

    module Data.ListLike.Utils
        (and, or, sum, product, zip, zipWith, unzip, sequence_, toMonadPlus, list,
         intercalate
        ) where
    import Prelude hiding (length, head, last, null, tail, map, filter, concat,
                           any, lookup, init, all, foldl, foldr, foldl1, foldr1,
                           maximum, minimum, iterate, span, break, takeWhile,
                           dropWhile, reverse, zip, zipWith, sequence,
                           sequence_, mapM, mapM_, concatMap, and, or, sum,
                           product, repeat, replicate, cycle, take, drop,
                           splitAt, elem, notElem, unzip, lines, words,
                           unlines, unwords, foldMap)
    import Control.Monad (MonadPlus(..))
    import Data.ListLike.Base
    import Data.ListLike.FoldableLL
    import Data.Monoid

    -- | Returns True if all elements are True
    and :: ListLike full Bool => full -> Bool
    and :: forall full. ListLike full Bool => full -> Bool
    and = (Bool -> Bool) -> full -> Bool
    forall full item.
    ListLike full item =>
    (item -> Bool) -> full -> Bool
    all (Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    True)

    -- | Returns True if any element is True
    or :: ListLike full Bool => full -> Bool
    or :: forall full. ListLike full Bool => full -> Bool
    or = (Bool -> Bool) -> full -> Bool
    forall full item.
    ListLike full item =>
    (item -> Bool) -> full -> Bool
    any (Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    True)

    -- | The sum of the list
    sum :: (Num a, ListLike full a) => full -> a
    sum :: forall a full. (Num a, ListLike full a) => full -> a
    sum = Sum a -> a
    forall a. Sum a -> a
    getSum (Sum a -> a) -> (full -> Sum a) -> full -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (a -> Sum a) -> full -> Sum a
    forall full item m.
    (FoldableLL full item, Monoid m) =>
    (item -> m) -> full -> m
    foldMap a -> Sum a
    forall a. a -> Sum a
    Sum

    -- | The product of the list
    product :: (Num a, ListLike full a) => full -> a
    product :: forall a full. (Num a, ListLike full a) => full -> a
    product = Product a -> a
    forall a. Product a -> a
    getProduct (Product a -> a) -> (full -> Product a) -> full -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (a -> Product a) -> full -> Product a
    forall full item m.
    (FoldableLL full item, Monoid m) =>
    (item -> m) -> full -> m
    foldMap a -> Product a
    forall a. a -> Product a
    Product

    ------------------------------ Zipping
    -- zip, zipWith  in Base
    {- | Converts a list of pairs into two separate lists of elements -}
    unzip :: (ListLike full (itema, itemb),
              ListLike ra itema,
              ListLike rb itemb) => full -> (ra, rb)
    unzip :: forall full itema itemb ra rb.
    (ListLike full (itema, itemb), ListLike ra itema,
     ListLike rb itemb) =>
    full -> (ra, rb)
    unzip full
    inp = ((itema, itemb) -> (ra, rb) -> (ra, rb))
    -> (ra, rb) -> full -> (ra, rb)
    forall b. ((itema, itemb) -> b -> b) -> b -> full -> b
    forall full item b.
    FoldableLL full item =>
    (item -> b -> b) -> b -> full -> b
    foldr (itema, itemb) -> (ra, rb) -> (ra, rb)
    (Item ra, Item rb) -> (ra, rb) -> (ra, rb)
    forall {a} {b}.
    (ListLike a (Item a), ListLike b (Item b)) =>
    (Item a, Item b) -> (a, b) -> (a, b)
    convert (ra
    forall full item. ListLike full item => full
    empty, rb
    forall full item. ListLike full item => full
    empty) full
    inp
        where convert :: (Item a, Item b) -> (a, b) -> (a, b)
    convert (Item a
    a, Item b
    b) (a
    as, b
    bs) = ((Item a -> a -> a
    forall full item. ListLike full item => item -> full -> full
    cons Item a
    a a
    as), (Item b -> b -> b
    forall full item. ListLike full item => item -> full -> full
    cons Item b
    b b
    bs))

    -- | Converts to a MonadPlus instance
    toMonadPlus :: (MonadPlus m, ListLike full a) => full -> m (a, full)
    toMonadPlus :: forall (m :: * -> *) full a.
    (MonadPlus m, ListLike full a) =>
    full -> m (a, full)
    toMonadPlus = m (a, full)
    -> ((a, full) -> m (a, full)) -> Maybe (a, full) -> m (a, full)
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe m (a, full)
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero (a, full) -> m (a, full)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (a, full) -> m (a, full))
    -> (full -> Maybe (a, full)) -> full -> m (a, full)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . full -> Maybe (a, full)
    forall full item. ListLike full item => full -> Maybe (item, full)
    uncons

    -- | List-like destructor (like Data.Maybe.maybe)
    list :: ListLike full a => b -> (a -> full -> b) -> full -> b
    list :: forall full a b.
    ListLike full a =>
    b -> (a -> full -> b) -> full -> b
    list b
    d a -> full -> b
    f = b -> ((a, full) -> b) -> Maybe (a, full) -> b
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe b
    d ((a -> full -> b) -> (a, full) -> b
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry a -> full -> b
    f) (Maybe (a, full) -> b) -> (full -> Maybe (a, full)) -> full -> b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . full -> Maybe (a, full)
    forall (m :: * -> *) full a.
    (MonadPlus m, ListLike full a) =>
    full -> m (a, full)
    toMonadPlus

    -- | 'intercalate' @xs xss@ is equivalent to @('concat' ('intersperse'
    -- xs xss))@.  It inserts the list @xs@ in between the lists in @xss@
    -- and concatenates the result.
    intercalate :: (ListLike a item, ListLike b a)
                => a -> b -> a
    intercalate :: forall a item b. (ListLike a item, ListLike b a) => a -> b -> a
    intercalate a
    x = b -> a
    forall full'. ListLike full' a => full' -> a
    forall full item full'.
    (ListLike full item, ListLike full' full) =>
    full' -> full
    concat (b -> a) -> (b -> b) -> b -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> b -> b
    forall full item. ListLike full item => item -> full -> full
    intersperse a
    x