{-# OPTIONS_HADDOCK ignore-exports #-}
{-# LANGUAGE Safe, CPP #-}

{- |
    Module      :  SDP.SafePrelude
    Copyright   :  (c) Andrey Mulik 2019-2021
    License     :  BSD-style
    Maintainer  :  work.a.mulik@gmail.com
    Portability :  portable
    
    "SDP.SafePrelude" module re-exports common "Prelude" definitions except
    those overridden in this library and its extensions (e.g. @sdp-io@).
    
    In addition, this module re-exports the most common definitions from other
    @base@ and @sdp@ modules ("Control.Applicative", "Data.Bifunctor",
    "SDP.Estimate", etc.) and some useful combinators that were used in this
    library and may be useful to its users.
    
    Import "Prelude" without conflicting functions, may require additional
    imports for functions overridden in other modules:
    
    > import Prelude ()
    > import SDP.SafePrelude
-}
module SDP.SafePrelude
(
  -- * Exports
  module Control.Applicative, liftA4, liftA5, liftA6,
  
  module Control.Monad.IO.Class, stToMIO,
  module Control.Monad.ST,
  module Control.Monad, liftM6,
  
  module Data.Functor.Classes,
  module Data.Bifunctor,
  module Data.Foldable,
  
  module SDP.Comparing,
  module SDP.Estimate,
  
  module Prelude,
  
#if !MIN_VERSION_base(4,11,0)
  Semigroup (..),
#endif
  
  -- * Combinators
  (.), id, on, (?), (?+), (?-), (?^), (?:), (+?), (...), (<=<<), (>>=>), (>>=<<)
)
where

import Prelude hiding
  (
    -- defined in Control.Category
    (.), id,
    
    -- defined in SDP.Zip and Data.List
    zip, zip3, zipWith, zipWith3,
    
    -- defined in SDP.Scan and Data.List
    scanl, scanr, scanl1, scanr1,
    
    -- defined in SDP.Linear and Data.List
    head, tail, init, last, take, drop, (!!), (++), reverse, filter, lookup,
    concat, concatMap, replicate, takeWhile, dropWhile, iterate,
    
    -- defined in System.IO.Handle, System.IO.Classes (@sdp-io@) and System.IO
    readFile, writeFile, appendFile, getContents,
    getChar, putChar, getLine, putStr, putStrLn
  )

import SDP.Comparing
import SDP.Estimate

#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup ( Semigroup (..) ) -- For base >= 4.9 && < 4.11
#endif

import Data.Functor.Classes

import Data.Bifunctor
import Data.Foldable hiding ( foldrM, foldlM, concat, concatMap )
import Data.Function ( on )

import Control.Applicative
import Control.Category

import Control.Monad.IO.Class
import Control.Monad.ST
import Control.Monad hiding ( zipWithM )

infixl 8 ?+, ?-
infixr 1 ?,  ?^ -- Lowest priority, compatible with infixr 0 $
infixr 0 ...

default ()

--------------------------------------------------------------------------------

{- |
  Ternary operator.
  
  > (odd 1 ? "is True" $ "is False") == "is True"
-}
{-# INLINE (?) #-}
(?) :: Bool -> a -> a -> a
? :: Bool -> a -> a -> a
(?) =  \ Bool
p a
t a
e -> if Bool
p then a
t else a
e

-- | @p ?+ f $ a@ returns @'Just' (f a)@ if @(p a)@ and 'Nothing' otherwise.
{-# INLINE (?+) #-}
(?+) :: (a -> Bool) -> (a -> b) -> a -> Maybe b
?+ :: (a -> Bool) -> (a -> b) -> a -> Maybe b
(?+) =  \ a -> Bool
p a -> b
f a
a -> a -> Bool
p a
a Bool -> Maybe b -> Maybe b -> Maybe b
forall a. Bool -> a -> a -> a
? b -> Maybe b
forall a. a -> Maybe a
Just (a -> b
f a
a) (Maybe b -> Maybe b) -> Maybe b -> Maybe b
forall a b. (a -> b) -> a -> b
$ Maybe b
forall a. Maybe a
Nothing

-- | @p ?- f $ a@ returns 'Nothing' if @(p a)@ and @'Just' (f a)@ otherwise.
{-# INLINE (?-) #-}
(?-) :: (a -> Bool) -> (a -> b) -> a -> Maybe b
?- :: (a -> Bool) -> (a -> b) -> a -> Maybe b
(?-) =  \ a -> Bool
p a -> b
f a
a -> a -> Bool
p a
a Bool -> Maybe b -> Maybe b -> Maybe b
forall a. Bool -> a -> a -> a
? Maybe b
forall a. Maybe a
Nothing (Maybe b -> Maybe b) -> Maybe b -> Maybe b
forall a b. (a -> b) -> a -> b
$ b -> Maybe b
forall a. a -> Maybe a
Just (a -> b
f a
a)

-- | Prepends 'Maybe' to list.
{-# INLINE (?:) #-}
(?:) :: Maybe a -> [a] -> [a]
?: :: Maybe a -> [a] -> [a]
(?:) =  \ Maybe a
mx [a]
xs -> case Maybe a
mx of {(Just a
x) -> a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
xs; Maybe a
_ -> [a]
xs}

-- | Short version of 'Data.Maybe.fromMaybe'.
{-# INLINE (+?) #-}
(+?) :: a -> Maybe a -> a
a
_ +? :: a -> Maybe a -> a
+? Just a
x = a
x
a
x +?      Maybe a
_ = a
x

-- | @(...) = (.) . (.)@.
{-# INLINE (...) #-}
(...) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
... :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(...) =  ((b -> c) -> b -> d) -> (a -> b -> c) -> a -> b -> d
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
(.) (((b -> c) -> b -> d) -> (a -> b -> c) -> a -> b -> d)
-> ((c -> d) -> (b -> c) -> b -> d)
-> (c -> d)
-> (a -> b -> c)
-> a
-> b
-> d
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (c -> d) -> (b -> c) -> b -> d
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
(.)

--------------------------------------------------------------------------------

{-# INLINE (?^) #-}
-- | Lifted @('?')@.
(?^) :: (Monad m) => m Bool -> m a -> m a -> m a
?^ :: m Bool -> m a -> m a -> m a
(?^) =  \ m Bool
mb m a
mt m a
me -> do Bool
b <- m Bool
mb; if Bool
b then m a
mt else m a
me

-- | Monadic version of @('...')@.
(<=<<) :: (Monad m) => (c -> m d) -> (a -> b -> m c) -> (a -> b -> m d)
<=<< :: (c -> m d) -> (a -> b -> m c) -> a -> b -> m d
(<=<<) =  \ c -> m d
mg a -> b -> m c
mf a
a b
b -> a -> b -> m c
mf a
a b
b m c -> (c -> m d) -> m d
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= c -> m d
mg

-- | Monadic vesion of @('...')@ with reversed arguments.
(>>=>) :: (Monad m) => (a -> b -> m c) -> (c -> m d) -> (a -> b -> m d)
>>=> :: (a -> b -> m c) -> (c -> m d) -> a -> b -> m d
(>>=>) =  \ a -> b -> m c
mf c -> m d
mg a
a b
b -> a -> b -> m c
mf a
a b
b m c -> (c -> m d) -> m d
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= c -> m d
mg

-- | @ma >>=<< mb@ is composition of 'join' and 'liftM2'.
{-# INLINE (>>=<<) #-}
(>>=<<) :: (Monad m) => m a -> m b -> (a -> b -> m c) -> m c
>>=<< :: m a -> m b -> (a -> b -> m c) -> m c
(>>=<<) = \ m a
ma m b
mb a -> b -> m c
f -> m (m c) -> m c
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join (m (m c) -> m c) -> m (m c) -> m c
forall a b. (a -> b) -> a -> b
$ (a -> b -> m c) -> m a -> m b -> m (m c)
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 a -> b -> m c
f m a
ma m b
mb

--------------------------------------------------------------------------------

-- | Very useful combinator.
liftA4 :: (Applicative t) => (a -> b -> c -> d -> e) -> t a -> t b -> t c -> t d -> t e
liftA4 :: (a -> b -> c -> d -> e) -> t a -> t b -> t c -> t d -> t e
liftA4 a -> b -> c -> d -> e
g t a
as t b
bs t c
cs t d
ds = a -> b -> c -> d -> e
g (a -> b -> c -> d -> e) -> t a -> t (b -> c -> d -> e)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> t a
as t (b -> c -> d -> e) -> t b -> t (c -> d -> e)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t b
bs t (c -> d -> e) -> t c -> t (d -> e)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t c
cs t (d -> e) -> t d -> t e
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t d
ds

-- | Very very useful combinator
liftA5 :: (Applicative t) => (a -> b -> c -> d -> e -> f) -> t a -> t b -> t c -> t d -> t e -> t f
liftA5 :: (a -> b -> c -> d -> e -> f)
-> t a -> t b -> t c -> t d -> t e -> t f
liftA5 a -> b -> c -> d -> e -> f
g t a
as t b
bs t c
cs t d
ds t e
es = a -> b -> c -> d -> e -> f
g (a -> b -> c -> d -> e -> f) -> t a -> t (b -> c -> d -> e -> f)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> t a
as t (b -> c -> d -> e -> f) -> t b -> t (c -> d -> e -> f)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t b
bs t (c -> d -> e -> f) -> t c -> t (d -> e -> f)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t c
cs t (d -> e -> f) -> t d -> t (e -> f)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t d
ds t (e -> f) -> t e -> t f
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t e
es

-- | An even more useful combinator.
liftA6 :: (Applicative t) => (a -> b -> c -> d -> e -> f -> g) -> t a -> t b -> t c -> t d -> t e -> t f -> t g
liftA6 :: (a -> b -> c -> d -> e -> f -> g)
-> t a -> t b -> t c -> t d -> t e -> t f -> t g
liftA6 a -> b -> c -> d -> e -> f -> g
g t a
as t b
bs t c
cs t d
ds t e
es t f
fs = a -> b -> c -> d -> e -> f -> g
g (a -> b -> c -> d -> e -> f -> g)
-> t a -> t (b -> c -> d -> e -> f -> g)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> t a
as t (b -> c -> d -> e -> f -> g) -> t b -> t (c -> d -> e -> f -> g)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t b
bs t (c -> d -> e -> f -> g) -> t c -> t (d -> e -> f -> g)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t c
cs t (d -> e -> f -> g) -> t d -> t (e -> f -> g)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t d
ds t (e -> f -> g) -> t e -> t (f -> g)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t e
es t (f -> g) -> t f -> t g
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t f
fs

-- | See 'liftA6'.
liftM6 :: (Monad m) => (a -> b -> c -> d -> e -> f -> g) -> m a -> m b -> m c -> m d -> m e -> m f -> m g
liftM6 :: (a -> b -> c -> d -> e -> f -> g)
-> m a -> m b -> m c -> m d -> m e -> m f -> m g
liftM6 a -> b -> c -> d -> e -> f -> g
g m a
as m b
bs m c
cs m d
ds m e
es m f
fs = do a
a <- m a
as; b
b <- m b
bs; c
c <- m c
cs; d
d <- m d
ds; e
e <- m e
es; f
f <- m f
fs; g -> m g
forall (m :: * -> *) a. Monad m => a -> m a
return (g -> m g) -> g -> m g
forall a b. (a -> b) -> a -> b
$ a -> b -> c -> d -> e -> f -> g
g a
a b
b c
c d
d e
e f
f

--------------------------------------------------------------------------------

-- | 'stToMIO' is just @'liftIO' . 'stToIO'@.
stToMIO :: (MonadIO io) => ST RealWorld e -> io e
stToMIO :: ST RealWorld e -> io e
stToMIO =  IO e -> io e
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO e -> io e)
-> (ST RealWorld e -> IO e) -> ST RealWorld e -> io e
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ST RealWorld e -> IO e
forall a. ST RealWorld a -> IO a
stToIO