cleff-0.3.0.0: src/Cleff/Fresh.hs
{-# LANGUAGE Trustworthy #-}
-- |
-- Copyright: (c) 2021 Xy Ren
-- License: BSD3
-- Maintainer: xy.r@outlook.com
-- Stability: experimental
-- Portability: non-portable (GHC only)
module Cleff.Fresh
( -- * Effect
Fresh (..)
-- * Operations
, fresh
-- * Interpretations
, freshIntToState
, freshEnumToState
, runFreshAtomicCounter
, runFreshUnique
) where
import Cleff
import Cleff.Internal.Base (thisIsPureTrustMe)
import Cleff.State
import Data.Atomics.Counter (incrCounter, newCounter)
import Data.Unique (Unique, newUnique)
-- * Effect
-- | An effect capable of generating unique values. This effect can be useful in generating variable indices.
data Fresh u :: Effect where
Fresh :: Fresh u m u
-- * Operations
makeEffect_ ''Fresh
-- | Obtain a fresh unique value.
fresh :: Fresh u :> es => Eff es u
-- * Interpretations
-- | Interpret a @'Fresh' a@ in terms of @'State' a@ for any 'Enum'. Every time 'succ' is called to generate the next
-- value.
--
-- @since 0.2.1.0
freshEnumToState :: Enum a => Eff (Fresh a ': es) ~> Eff (State a ': es)
freshEnumToState = reinterpret \case
Fresh -> state \s -> (s, succ s)
{-# INLINE freshEnumToState #-}
-- | Interpret a @'Fresh' 'Int'@ effect in terms of @'State' 'Int'@. This is a specialized version of
-- 'freshEnumToState'.
freshIntToState :: Eff (Fresh Int ': es) ~> Eff (State Int ': es)
freshIntToState = freshEnumToState
{-# INLINE freshIntToState #-}
-- | Interpret a @'Fresh' 'Int'@ effect in terms of a 'Data.Atomics.Counter.AtomicCounter'. This is usually faster
-- than 'runFreshUnique'.
--
-- @since 0.2.1.0
runFreshAtomicCounter :: Eff (Fresh Int ': es) ~> Eff es
runFreshAtomicCounter m = thisIsPureTrustMe do
counter <- liftIO $ newCounter minBound
reinterpret (\case
Fresh -> liftIO $ incrCounter 1 counter) m
{-# INLINE runFreshAtomicCounter #-}
-- | Interpret a @'Fresh' 'Unique'@ effect in terms of IO actions. This is slower than 'runFreshAtomicCounter', but it
-- won't overflow on @'maxBound' :: 'Int'@.
runFreshUnique :: IOE :> es => Eff (Fresh Unique ': es) ~> Eff es
runFreshUnique = interpret \case
Fresh -> liftIO newUnique
{-# INLINE runFreshUnique #-}