packages feed

himari-1.1.2.0: src/Himari/Env.hs

{-# LANGUAGE Trustworthy #-}

-- | Core environment monad for Himari.
module Himari.Env
  ( Himari (..)
  , runHimari
  , liftHimari
  , mapHimari
  ) where

import Control.Lens.Internal.Zoom (Effect) -- 直接の`UndecidableInstances`の回避のためInternal許容。
import Himari.Prelude

-- | The Reader + IO monad.
-- It is nearly equal to @RIO@ from the rio package.
newtype Himari env a = Himari
  { unHimari :: ReaderT env IO a
  }
  deriving newtype
    ( Applicative
    , Functor
    , Monad
    , MonadIO
    , MonadReader env
    , MonadThrow
    , MonadUnliftIO
    )

instance (Semigroup a) => Semigroup (Himari env a) where
  (<>) = liftA2 (<>)

instance (Monoid a) => Monoid (Himari env a) where
  mempty = pure mempty

instance PrimMonad (Himari env) where
  type PrimState (Himari env) = PrimState IO
  primitive = Himari . ReaderT . const . primitive

type instance Magnified (Himari e) = Effect IO

instance Magnify (Himari s) (Himari t) s t where
  magnify l (Himari m) = Himari $ magnify l m

-- | Given an environment, runs the action that requires it in IO.
runHimari :: (MonadIO m) => env -> Himari env a -> m a
runHimari env (Himari (ReaderT f)) = liftIO (f env)

-- | Abstract `Himari` to an arbitrary `MonadReader` instance, which can handle IO.
liftHimari :: (MonadIO m, MonadReader env m) => Himari env a -> m a
liftHimari rio = do
  env <- ask
  runHimari env rio

-- | Lift one Himari env to another.
mapHimari :: (outer -> inner) -> Himari inner a -> Himari outer a
mapHimari f m = do
  outer <- ask
  runHimari (f outer) m