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

{- |
    Module      :  SDP.SafePrelude
    Copyright   :  (c) Andrey Mulik 2019
    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.Bufunctor",
    "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,
  
  -- * Combinators
  on, (?), (?+), (?-), (?^), (?:), (+?), (...), (<=<<), (>>=>), (>>=<<)
)
where

import Prelude hiding
  (
    -- 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

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

import Control.Applicative

import Control.Monad.IO.Class
import Control.Monad.ST
import Control.Monad

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
Nothing = 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 b c a. (b -> c) -> (a -> b) -> 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 b c a. (b -> c) -> (a -> b) -> a -> c
. (c -> d) -> (b -> c) -> b -> d
forall b c a. (b -> c) -> (a -> b) -> 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 b c a. (b -> c) -> (a -> b) -> a -> c
. ST RealWorld e -> IO e
forall a. ST RealWorld a -> IO a
stToIO