-- | @avail@ is a companion to monad transformers that allows you to add effect management to /concrete monads/, -- i.e. specify what effects a piece of code can perform. -- -- Traditionally, in order to manage effects, the /effect typeclasses/ are placed on a polymorphic monad type -- @m@ so that other details of the monad type is not known at that point, effectively limiting what a function can do: -- -- @ -- (MonadWriter Log m, MonadState Store m, MonadReader Env m) => m () -- @ -- -- While this works well, it has inevitable performance drawback because of the polymorphic @m@. GHC doesn't know the -- implementation of @m@, hence cannot perform much optimization. On the other hand, if we use a concrete monad stack -- that supports all the effects we need, we will not be able to restrict the effects that can be performed. -- -- @avail@ addresses this by a monad transformer 'M'. For any monad @m@, the monad type @'M' m@ adds effect -- management on top of it. Specifically, for an effect typeclass @c@ (such as 'Control.Monad.MonadIO' or -- @'Control.Monad.Reader.MonadReader' r@), its methods can be used on @'M' m@ only if: -- -- * The monad @m@ actually supports the effect, i.e. has an instance @c m@ of the effect typeclass; -- * The effect is /available/ in current context, i.e. a /phantom constraint/ @'Eff' c@ (which doesn't contain any -- information) is added to the function signature. -- -- This pattern was first outlined in the blog post -- [/Effect is a phantom/](https://喵.世界/2021/09/14/redundant-constraints/). -- In @avail@, it allows you to manage effects via the phantom 'Eff' constraint while still using a -- concrete monad stack; the 'Eff' constarint is not tied to the stack anyhow. Finally, 'Eff' has no instances, -- and can only be removed all at once via the 'runM' function, obtaining the underlying monad. -- -- @avail@ supports libraries including @mtl@, @unliftio@, @monad-control@ and @capability@ out of the box, so there -- should be near-zero boilerplate to get started with @avail@. For other effect typeclasses, the @avail@ support -- of them can be easily derived via the TH functions in "Avail.Derive". -- -- You need these language extensions when using this module: -- -- @ -- DataKinds -- FlexibleContexts -- FlexibleInstances -- RankNTypes -- TypeApplications -- @ -- -- You need more extensions when using "Avail.Derive"; see documentation in that module. module Avail ( M, Effect, IsEff (Superclasses), Eff, Effs, KnownList, unM, runM ) where import Avail.Instances () import Avail.Internal