-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add IORef-based carrier for the Accum effect. #430
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
310eb80
Add IORef-based carrier for the Accum effect.
patrickt 40db8c8
Clarify changelog.
patrickt 3cd4659
Fix GHC 8.2.
patrickt 32a9eb2
Monoid is too strict here, we can get by with Semigroup.
patrickt 58e4f82
Fix docs.
patrickt 520d27b
Fix docs again.
patrickt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE GADTs #-} | ||
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
{-# LANGUAGE MultiParamTypeClasses #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
{-# LANGUAGE TypeOperators #-} | ||
{-# LANGUAGE UndecidableInstances #-} | ||
|
||
{- | A carrier for 'Accum' effects. | ||
This carrier performs its append operations strictly and thus avoids the space leaks inherent in lazy writer monads. | ||
These appends are left-associative; as such, @[]@ is a poor choice of monoid for computations that entail many calls to 'add'. | ||
The [Seq](http://hackage.haskell.org/package/containersdocs/Data-Sequence.html) or [DList](http://hackage.haskell.org/package/dlist) monoids may be a superior choice. | ||
This carrier also uses an 'IORef' to store its accumulator, which allows it a 'MonadUnliftIO' instance, but precludes backtracking when run in conjunction with 'Control.Effect.NonDet'. | ||
|
||
-- | @since 1.1.2.0 | ||
-} | ||
|
||
module Control.Carrier.Accum.IORef | ||
( -- * Accum carrier | ||
runAccum | ||
, execAccum | ||
, evalAccum | ||
, AccumC(AccumC) | ||
-- * Accum effect | ||
, module Control.Effect.Accum | ||
) where | ||
|
||
import Control.Algebra | ||
import Control.Applicative (Alternative(..)) | ||
import Control.Effect.Accum | ||
import Control.Monad (MonadPlus(..)) | ||
import Control.Monad.Fail as Fail | ||
import Control.Monad.Fix | ||
import Control.Monad.IO.Class | ||
import Control.Monad.Trans.Class | ||
import Data.IORef | ||
import qualified Data.Semigroup as S | ||
import Control.Monad.IO.Unlift (MonadUnliftIO) | ||
import Control.Carrier.Reader | ||
|
||
-- | Run an 'Accum' effect with a 'Semigroup'-based log. | ||
-- | ||
-- @ | ||
-- 'runAccum' w0 ('pure' a) = 'pure' (w0, a) | ||
-- @ | ||
-- @ | ||
-- 'runAccum' w0 ('add' w) = 'pure' (w0 <> w, ()) | ||
-- @ | ||
-- @ | ||
-- 'runAccum' w0 ('add' w >> 'look') = 'pure' (w0 <> w, w0 <> w) | ||
-- @ | ||
-- | ||
-- @since 1.1.2.0 | ||
runAccum :: MonadIO m => w -> AccumC w m a -> m (w, a) | ||
runAccum start go = do | ||
ref <- liftIO (newIORef start) | ||
result <- runReader ref . runAccumC $ go | ||
final <- liftIO (readIORef ref) | ||
pure (final, result) | ||
{-# INLINE runAccum #-} | ||
|
||
-- | Run a 'Accum' effect with a 'Semigroup'-based log, | ||
-- producing the final log and discarding the result value. | ||
-- | ||
-- @ | ||
-- 'execAccum' w = 'fmap' 'fst' . 'runAccum' w | ||
-- @ | ||
-- | ||
-- @since 1.1.2.0 | ||
execAccum :: MonadIO m => w -> AccumC w m a -> m w | ||
execAccum w = fmap fst . runAccum w | ||
{-# INLINE execAccum #-} | ||
|
||
-- | Run a 'Accum' effect with a 'Semigroup'-based log, | ||
-- producing the result value and discarding the final log. | ||
-- | ||
-- @ | ||
-- 'evalAccum' w = 'fmap' 'snd' . 'runAccum' w | ||
-- @ | ||
-- | ||
-- @since 1.1.2.0 | ||
evalAccum :: MonadIO m => w -> AccumC w m a -> m a | ||
evalAccum w = fmap snd . runAccum w | ||
{-# INLINE evalAccum #-} | ||
|
||
-- | @since 1.1.2.0 | ||
newtype AccumC w m a = AccumC { runAccumC :: ReaderC (IORef w) m a } | ||
deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus, MonadTrans, MonadUnliftIO) | ||
|
||
instance (Algebra sig m, S.Semigroup w, MonadIO m) => Algebra (Accum w :+: sig) (AccumC w m) where | ||
alg hdl sig ctx = case sig of | ||
L accum -> do | ||
ref <- AccumC (ask @(IORef w)) | ||
(<$ ctx) <$> case accum of | ||
Add w' -> liftIO (modifyIORef' ref (S.<> w')) | ||
Look -> liftIO (readIORef ref) | ||
Comment on lines
+96
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could factor out the |
||
R other -> AccumC (alg (runAccumC . hdl) (R other) ctx) | ||
{-# INLINE alg #-} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sometimes I prefer to do this sort of thing by constructing the
ReaderC
directly instead ofask
ing with a type application, e.g.:I'm not fussed either way.