{-# LANGUAGE DerivingVia #-}

{- |
Module                  : Iris.App
Copyright               : (c) 2022 Dmitrii Kovanikov
SPDX-License-Identifier : MPL-2.0
Maintainer              : Dmitrii Kovanikov <kovanikov@gmail.com>
Stability               : Experimental
Portability             : Portable

The application monad — 'CliApp'.

Many functions in __Iris__ are polymorphic over any monad that has the 'MonadReader' constraint.

Implement your own application monad as a __newtype__ wrapper around 'CliApp' in
the following way.

@
__newtype__ App a = App
    { unApp :: Iris.'CliApp' MyOptions MyEnv a
    } __deriving newtype__
        ( 'Functor'
        , 'Applicative'
        , 'Monad'
        , 'MonadIO'
        , 'MonadUnliftIO'
        , 'MonadReader' (Iris.'CliEnv' MyOptions MyEnv)
        )
@

@since 0.0.0.0
-}
module Iris.App (
    CliApp (..),
    runCliApp,
    runCliAppManually,
) where

import Control.Monad.IO.Class (MonadIO)
import Control.Monad.IO.Unlift (MonadUnliftIO)
import Control.Monad.Reader (MonadReader, ReaderT (..))

import Iris.Env (CliEnv, mkCliEnv)
import Iris.Settings (CliEnvSettings)

{- | Main monad for your CLI application.

The type variables are:

* @cmd@: the data type for your CLI arguments
* @appEnv@: custom environment for your application (can be just @()@ if you
  don't need one)
* @a@: the value inside the monadic context

@since 0.0.0.0
-}
newtype CliApp cmd appEnv a = CliApp
    { forall cmd appEnv a.
CliApp cmd appEnv a -> CliEnv cmd appEnv -> IO a
unCliApp :: CliEnv cmd appEnv -> IO a
    }
    deriving
        ( forall a b. a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
forall a b. (a -> b) -> CliApp cmd appEnv a -> CliApp cmd appEnv b
forall cmd appEnv a b.
a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
forall cmd appEnv a b.
(a -> b) -> CliApp cmd appEnv a -> CliApp cmd appEnv b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
$c<$ :: forall cmd appEnv a b.
a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
fmap :: forall a b. (a -> b) -> CliApp cmd appEnv a -> CliApp cmd appEnv b
$cfmap :: forall cmd appEnv a b.
(a -> b) -> CliApp cmd appEnv a -> CliApp cmd appEnv b
Functor
          -- ^ @since 0.0.0.0
        , forall a. a -> CliApp cmd appEnv a
forall cmd appEnv. Functor (CliApp cmd appEnv)
forall a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
forall a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
forall a b.
CliApp cmd appEnv (a -> b)
-> CliApp cmd appEnv a -> CliApp cmd appEnv b
forall cmd appEnv a. a -> CliApp cmd appEnv a
forall a b c.
(a -> b -> c)
-> CliApp cmd appEnv a
-> CliApp cmd appEnv b
-> CliApp cmd appEnv c
forall cmd appEnv a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
forall cmd appEnv a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
forall cmd appEnv a b.
CliApp cmd appEnv (a -> b)
-> CliApp cmd appEnv a -> CliApp cmd appEnv b
forall cmd appEnv a b c.
(a -> b -> c)
-> CliApp cmd appEnv a
-> CliApp cmd appEnv b
-> CliApp cmd appEnv c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
$c<* :: forall cmd appEnv a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv a
*> :: forall a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
$c*> :: forall cmd appEnv a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
liftA2 :: forall a b c.
(a -> b -> c)
-> CliApp cmd appEnv a
-> CliApp cmd appEnv b
-> CliApp cmd appEnv c
$cliftA2 :: forall cmd appEnv a b c.
(a -> b -> c)
-> CliApp cmd appEnv a
-> CliApp cmd appEnv b
-> CliApp cmd appEnv c
<*> :: forall a b.
CliApp cmd appEnv (a -> b)
-> CliApp cmd appEnv a -> CliApp cmd appEnv b
$c<*> :: forall cmd appEnv a b.
CliApp cmd appEnv (a -> b)
-> CliApp cmd appEnv a -> CliApp cmd appEnv b
pure :: forall a. a -> CliApp cmd appEnv a
$cpure :: forall cmd appEnv a. a -> CliApp cmd appEnv a
Applicative
          -- ^ @since 0.0.0.0
        , forall a. a -> CliApp cmd appEnv a
forall cmd appEnv. Applicative (CliApp cmd appEnv)
forall a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
forall a b.
CliApp cmd appEnv a
-> (a -> CliApp cmd appEnv b) -> CliApp cmd appEnv b
forall cmd appEnv a. a -> CliApp cmd appEnv a
forall cmd appEnv a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
forall cmd appEnv a b.
CliApp cmd appEnv a
-> (a -> CliApp cmd appEnv b) -> CliApp cmd appEnv b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> CliApp cmd appEnv a
$creturn :: forall cmd appEnv a. a -> CliApp cmd appEnv a
>> :: forall a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
$c>> :: forall cmd appEnv a b.
CliApp cmd appEnv a -> CliApp cmd appEnv b -> CliApp cmd appEnv b
>>= :: forall a b.
CliApp cmd appEnv a
-> (a -> CliApp cmd appEnv b) -> CliApp cmd appEnv b
$c>>= :: forall cmd appEnv a b.
CliApp cmd appEnv a
-> (a -> CliApp cmd appEnv b) -> CliApp cmd appEnv b
Monad
          -- ^ @since 0.0.0.0
        , forall a. IO a -> CliApp cmd appEnv a
forall cmd appEnv. Monad (CliApp cmd appEnv)
forall cmd appEnv a. IO a -> CliApp cmd appEnv a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> CliApp cmd appEnv a
$cliftIO :: forall cmd appEnv a. IO a -> CliApp cmd appEnv a
MonadIO
          -- ^ @since 0.0.0.0
        , MonadReader (CliEnv cmd appEnv)
          -- ^ @since 0.0.0.0
        , forall b.
((forall a. CliApp cmd appEnv a -> IO a) -> IO b)
-> CliApp cmd appEnv b
forall cmd appEnv. MonadIO (CliApp cmd appEnv)
forall cmd appEnv b.
((forall a. CliApp cmd appEnv a -> IO a) -> IO b)
-> CliApp cmd appEnv b
forall (m :: * -> *).
MonadIO m
-> (forall b. ((forall a. m a -> IO a) -> IO b) -> m b)
-> MonadUnliftIO m
withRunInIO :: forall b.
((forall a. CliApp cmd appEnv a -> IO a) -> IO b)
-> CliApp cmd appEnv b
$cwithRunInIO :: forall cmd appEnv b.
((forall a. CliApp cmd appEnv a -> IO a) -> IO b)
-> CliApp cmd appEnv b
MonadUnliftIO
          -- ^ @since 0.0.0.0
        )
        via ReaderT (CliEnv cmd appEnv) IO

{- | Run application with settings.

This function is supposed to be used in your @main@ function:

@
app :: App ()
app = ... your main application ...

main :: IO ()
main = 'runCliApp' mySettings (unApp app)
@

@since 0.0.0.0
-}
runCliApp :: CliEnvSettings cmd appEnv -> CliApp cmd appEnv a -> IO a
runCliApp :: forall cmd appEnv a.
CliEnvSettings cmd appEnv -> CliApp cmd appEnv a -> IO a
runCliApp CliEnvSettings cmd appEnv
settings CliApp cmd appEnv a
cliApp = do
    CliEnv cmd appEnv
cliEnv <- forall cmd appEnv.
CliEnvSettings cmd appEnv -> IO (CliEnv cmd appEnv)
mkCliEnv CliEnvSettings cmd appEnv
settings
    forall cmd appEnv a.
CliEnv cmd appEnv -> CliApp cmd appEnv a -> IO a
runCliAppManually CliEnv cmd appEnv
cliEnv CliApp cmd appEnv a
cliApp

{- | Run application by constructing 'CliEnv' settings manually.

@since 0.0.0.0
-}
runCliAppManually :: CliEnv cmd appEnv -> CliApp cmd appEnv a -> IO a
runCliAppManually :: forall cmd appEnv a.
CliEnv cmd appEnv -> CliApp cmd appEnv a -> IO a
runCliAppManually CliEnv cmd appEnv
cliEnv (CliApp CliEnv cmd appEnv -> IO a
run) = CliEnv cmd appEnv -> IO a
run CliEnv cmd appEnv
cliEnv