module Effectful
( -- * Introduction
-- $intro
-- ** Integration with existing libraries
-- $integration
-- *** Transformed monads
-- $transformer
-- *** Concrete monads
-- **** IO
-- $concrete_io
-- **** Other
-- $concrete_other
-- *** Polymorphic monads
-- $poly
-- * The 'Eff' monad
Eff
-- ** Effect constraints
, Effect
, Dispatch(..)
, DispatchOf
, (:>)
, (:>>)
-- * Running the 'Eff' monad
-- ** Pure computations
, runPureEff
-- ** Computations with side effects
, runEff
, IOE
-- ** Unlifting
, UnliftStrategy(..)
, Persistence(..)
, Limit(..)
, unliftStrategy
, withUnliftStrategy
, withEffToIO
, withSeqEffToIO
, withConcEffToIO
-- ** Lifting
, raise
, raiseWith
, subsume
, inject
, Subset
-- * Re-exports
, MonadIO(..)
, MonadUnliftIO(..)
) where
import Control.Monad.IO.Class
import Control.Monad.IO.Unlift
import Effectful.Internal.Effect
import Effectful.Internal.Env
import Effectful.Internal.Monad
-- $intro
--
-- Haskell is one of the few programming languages that distinguishes between
-- pure functions and functions that might perform side effects. For example, a
-- function
--
-- @
-- f :: 'Int' -> 'String'
-- @
--
-- can't perform side effects at all, but a function
--
-- @
-- f :: 'Int' -> 'IO' 'String'
-- @
--
-- can perform any side effect. This "all or nothing" approach isn't very
-- satisfactory though, because the vast majority of time we would like to
-- signify that a function can perform /some/ side effects, e.g. only be able to
-- log messages.
--
-- This library provides support for expressing exactly that with its 'Eff'
-- monad:
--
-- @
-- f :: Log ':>' es => 'Int' -> 'Eff' es 'String'
-- @
--
-- It implements support for extensible effects with both dynamic and static
-- dispatch. For more information about each type consult the documentation in
-- "Effectful.Dispatch.Dynamic" and "Effectful.Dispatch.Static".
--
-- The library provides:
--
-- - The 'Eff' monad that tracks effects at the type level. This is going to be
-- the main monad of your application.
--
-- - A set of predefined, basic effects such as t'Effectful.Error.Static.Error',
-- t'Effectful.Reader.Static.Reader', t'Effectful.State.Static.Local.State' and
-- t'Effectful.Writer.Static.Local.Writer'.
--
-- - Utilities for defining new effects and interpreting them, possibly in terms
-- of already existing ones.
--
-- While basic effects can be used out of the box, in general it's recommended
-- to create your own that serve a more specific purpose.
--
-- $integration
--
-- Integration with most of existing libraries and frameworks can be done quite
-- easily. The main difference in how that looks like depends on the way a
-- library operates in a monadic context.
--
-- There are three main groups a library might fall into. It either operates:
--
-- 1) In a monad of your application transformed by a library specific monad
-- transformer.
--
-- 2) In its own, concrete monad, which is usually 'IO' or a couple of monad
-- transformers on top of 'IO'.
--
-- 3) In a polymorphic monad, which is constrained by a type class that
-- implements core operations of a library.
--
-- Each case needs a slightly different approach to integrate with the 'Eff'
-- monad.
-- $transformer
--
-- These are libraries that provide a custom transformer for the main monad of
-- your application and their operations make use of it for their
-- operations. Examples include @InputT@ from the
-- [haskeline](https://hackage.haskell.org/package/haskeline) package or
-- @ConduitT@ from the [conduit](https://hackage.haskell.org/package/conduit)
-- package.
--
-- These libraries can trivially be used with the 'Eff' monad since it provides
-- typical instances that these libraries require the underlying monad to have,
-- such as t'Control.Monad.Catch.MonadMask' or 'MonadUnliftIO'.
--
-- In case the 'Eff' monad doesn't provide a specific instance out of the box,
-- it can be supplied via an effect. As an example see how the instance of
-- @MonadResource@ for 'Eff' is implemented in the
-- [resourcet-effectful](https://hackage.haskell.org/package/resourcet-effectful)
-- package.
--
-- $concrete_io
--
-- If a library operates in 'IO', there are a couple of ways to integrate it.
--
-- The easiest way is to use its functions selectively in the 'Eff' monad with
-- the help of 'liftIO' or 'withEffToIO' / 'withRunInIO'. However, this is not
-- particularly robust, since it vastly broadens the scope in which the 'IOE'
-- effect is needed (not to mention that explicit lifting is annoying).
--
-- A somewhat better approach is to create a dummy static effect with
-- lightweight wrappers of the library functions. As an example have a look at
-- the
-- [@Effectful.Concurrent.Async@](https://hackage.haskell.org/package/effectful/docs/Effectful-Concurrent-Async.html)
-- module from the [effectful](https://hackage.haskell.org/package/effectful)
-- package that wraps the API of the
-- [async](https://hackage.haskell.org/package/async) package. Unfortunately,
-- this requires the amount of work proportional to the size of the library and
-- might not be the best option, especially if you only need to make use of a
-- tiny portion of the API.
--
-- Even better (though sometimes hard to do in practice) way is to consider,
-- what do you need the library for and then create a custom effect with high
-- level operations that the library in question will help us implement. The
-- advantage of this approach is that we're hiding implementation details from
-- the so-called "business logic" of our application and make it possible to
-- easily swap them in different environments or during future refactoring.
--
-- $concrete_other
--
-- Some libraries operate in a transformer stack over 'IO' or have its own
-- concrete monad that's a newtype over 'IO', e.g. @Handler@ from the
-- [servant-server](https://hackage.haskell.org/package/servant-server) package.
--
-- In such case it's best to mirror the monad in question by the 'Eff' monad
-- with appropriate effects (as most popular monad transformers have [subtle
-- issues](https://github.com/haskell-effectful/effectful/blob/master/transformers.md)),
-- use it as soon as possible, then at the end feed the final state to the monad
-- of the library so it proceeds as if nothing unusual happened.
--
-- As an example, consider the following monad:
--
-- >>> import qualified Control.Monad.State as T
-- >>> import qualified Control.Monad.Except as T
--
-- >>> data HandlerState
-- >>> data HandlerError
--
-- >>> :{
-- newtype Handler a = Handler (T.ExceptT HandlerError (T.StateT HandlerState IO) a)
-- deriving ( Applicative, Functor, Monad, MonadIO
-- , T.MonadState HandlerState, T.MonadError HandlerError
-- )
-- :}
--
-- This is how you can execute 'Eff' actions in the @Handler@ monad:
--
-- >>> import Effectful.Error.Static
-- >>> import Effectful.State.Static.Local
--
-- >>> :{
-- effToHandler :: Eff [Error HandlerError, State HandlerState, IOE] a -> Handler a
-- effToHandler m = do
-- -- Retrieve the current state of the Handler.
-- s <- T.get
-- -- Run the Eff monad with effects mirroring the capabilities of @Handler@.
-- (er, s') <- liftIO . runEff . runState s . runErrorNoCallStack @HandlerError $ m
-- -- Update the state of the Handler and throw an error if appropriate.
-- T.put s'
-- either T.throwError pure er
-- :}
--
-- $poly
--
-- Libraries working in a polymorphic monad use @mtl@ style effects. Details
-- about their integration with the 'Eff' monad require familiarity with
-- dynamically dispatched effects and thus are available in the
-- "Effectful.Dispatch.Dynamic#integration" module.
--