polysemy-0.1.2.0: src/Polysemy.hs
module Polysemy
( -- * Core Types
Sem ()
, Member
, Members
-- * Running Sem
, run
, runM
-- * Interoperating With Other Monads
, Lift (..)
, sendM
-- * Lifting
, raise
-- * Creating New Effects
-- | Effects should be defined as a GADT (enable @-XGADTs@), with kind @(*
-- -> *) -> * -> *@. Every primitive action in the effect should be its
-- own constructor of the type. For example, we can model an effect which
-- interacts with a tty console as follows:
--
-- @
-- data Console m a where
-- WriteLine :: String -> Console m ()
-- ReadLine :: Console m String
-- @
--
-- Notice that the @a@ parameter gets instataniated at the /desired return
-- type/ of the actions. Writing a line returns a '()', but reading one
-- returns 'String'.
--
-- By enabling @-XTemplateHaskell@, we can use the 'makeSem' function
-- to generate smart constructors for the actions. These smart constructors
-- can be invoked directly inside of the 'Sem' monad.
--
-- >>> makeSem ''Console
--
-- results in the following definitions:
--
-- @
-- writeLine :: 'Member' Console r => String -> 'Sem' r ()
-- readLine :: 'Member' Console r => 'Sem' r String
-- @
--
-- Effects which don't make use of the @m@ parameter are known as
-- "first-order effects."
-- ** Higher-Order Effects
-- | Every effect has access to the @m@ parameter, which corresponds to the
-- 'Sem' monad it's used in. Using this parameter, we're capable of
-- writing effects which themselves contain subcomputations.
--
-- For example, the definition of 'Polysemy.Error.Error' is
--
-- @
-- data 'Polysemy.Error.Error' e m a where
-- 'Polysemy.Error.Throw' :: e -> 'Polysemy.Error.Error' e m a
-- 'Polysemy.Error.Catch' :: m a -> (e -> m a) -> 'Polysemy.Error.Error' e m a
-- @
--
-- where 'Polysemy.Error.Catch' is an action that can run an exception
-- handler if its first argument calls 'Polysemy.Error.throw'.
--
-- >>> makeSem ''Error
--
-- @
-- 'Polysemy.Error.throw' :: 'Member' ('Polysemy.Error.Error' e) r => e -> 'Sem' r a
-- 'Polysemy.Error.catch' :: 'Member' ('Polysemy.Error.Error' e) r => 'Sem' r a -> (e -> 'Sem' r a) -> 'Sem' r a
-- @
--
-- As you see, in the smart constructors, the @m@ parameter has become @'Sem' r@.
, makeSem
, makeSem_
-- * Combinators for Interpreting First-Order Effects
, interpret
, intercept
, reinterpret
, reinterpret2
, reinterpret3
-- * Combinators for Interpreting Higher-Order Effects
, interpretH
, interceptH
, reinterpretH
, reinterpret2H
, reinterpret3H
-- * Improving Performance for Interpreters
, inlineRecursiveCalls
-- * Composing IO-based Interpreters
, (.@)
, (.@@)
-- * Tactics
-- | Higher-order effects need to explicitly thread /other effects'/ state
-- through themselves. Tactics are a domain-specific language for describing
-- exactly how this threading should take place.
--
-- The first computation to be run should use 'runT', and subsequent
-- computations /in the same environment/ should use 'bindT'. Any
-- first-order constructors which appear in a higher-order context may use
-- 'pureT' to satisfy the typechecker.
, Tactical
, WithTactics
, getInitialStateT
, pureT
, runT
, bindT
-- * Deprecated Names
-- | The following exports are deprecated, and are exposed only for
-- backwards compatability reasons. They will be removed in the next major
-- release.
, Semantic
, runSemantic
, makeSemantic
, makeSemantic_
) where
import Polysemy.Internal
import Polysemy.Internal.Combinators
import Polysemy.Internal.TH.Effect
import Polysemy.Internal.TH.Performance
import Polysemy.Internal.Tactics
-- Imported just for the deprecated names.
import Polysemy.Internal.Union
import Language.Haskell.TH
--------------------------------------------------------------------------------
-- Deprecated names
type Semantic = Sem
{-# DEPRECATED Semantic "Use 'Sem' instead" #-}
runSemantic :: ∀ m r a
. Monad m
=> Semantic r a -> (∀ x. Union r (Sem r) x -> m x)
-> m a
runSemantic = runSem
{-# DEPRECATED runSemantic "Use 'runSem' instead" #-}
makeSemantic :: Name -> Q [Dec]
makeSemantic = makeSem
{-# DEPRECATED makeSemantic "Use 'makeSem' instead" #-}
makeSemantic_ :: Name -> Q [Dec]
makeSemantic_ = makeSem_
{-# DEPRECATED makeSemantic_ "Use 'makeSem_' instead" #-}