capability-0.1.0.0: Extensional capabilities and deriving combinators

Safe HaskellNone
LanguageHaskell2010

Capability.Writer

Contents

Description

Defines a capability type class for writer effects. A writer program can output values with tell. The values output by two consecutive sub-computation are combined using a monoid's mappend.

The interface of HasWriter follows that of MonadWriter. However, this module does not include a strategy to provide a HasWriter capability from a MonadWriter instance. It is generally a bad idea to use monads such as WriterT, as they tend to leak space, as described in this <https://blog.infinitenegativeutility.com/2016/7/writer-monads-and-space-leaks blog post> by Getty Ritter.

Instead, you should use the WriterLog strategy that implements the writer monad on a state monad. There is no downside, as using HasWriter instead of HasState directly ensures your code adheres to the writer monad interface and does not misuse the underlying state monad.

Synopsis

Interface

class (Monoid w, Monad m) => HasWriter (tag :: k) (w :: *) (m :: * -> *) | tag m -> w where Source #

Writer capability

An instance should fulfill the following laws. At this point these laws are not definitive, see https://github.com/haskell/mtl/issues/5.

listen @t (pure a) = pure (a, mempty)
listen @t (tell @t w) = tell @t w >> pure (w, w)
listen @t (m >>= k) = listen @t m >>= \(a, w1) -> listen @t (k a) >>= \(b, w2) -> pure (b, w1 `mappend` w2)
pass @t (tell @t w >> pure (a, f)) = tell @t (f w) >> pure a
writer @t (a, w) = tell @t w >> pure a

Methods

writer_ :: Proxy# tag -> (a, w) -> m a Source #

For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use writer. See writer for more documentation.

tell_ :: Proxy# tag -> w -> m () Source #

For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use tell. See tell for more documentation.

listen_ :: Proxy# tag -> m a -> m (a, w) Source #

For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use listen. See listen for more documentation.

pass_ :: Proxy# tag -> m (a, w -> w) -> m a Source #

For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use pass. See pass for more documentation.

Instances
(Monoid w, HasState tag w m) => HasWriter (tag :: k) w (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Methods

writer_ :: Proxy# tag -> (a, w) -> WriterLog m a Source #

tell_ :: Proxy# tag -> w -> WriterLog m () Source #

listen_ :: Proxy# tag -> WriterLog m a -> WriterLog m (a, w) Source #

pass_ :: Proxy# tag -> WriterLog m (a, w -> w) -> WriterLog m a Source #

(forall x. Coercible (m x) (t2 (t1 m) x), Monad m, HasWriter tag w (t2 (t1 m))) => HasWriter (tag :: k) w ((t2 :.: t1) m) Source #

Compose two accessors.

Instance details

Defined in Capability.Writer

Methods

writer_ :: Proxy# tag -> (a, w) -> (t2 :.: t1) m a Source #

tell_ :: Proxy# tag -> w -> (t2 :.: t1) m () Source #

listen_ :: Proxy# tag -> (t2 :.: t1) m a -> (t2 :.: t1) m (a, w) Source #

pass_ :: Proxy# tag -> (t2 :.: t1) m (a, w -> w) -> (t2 :.: t1) m a Source #

(HasWriter tag w m, MonadTransUnlift t, Monad (t m)) => HasWriter (tag :: Type) w (Lift (t m)) Source #

Lift one layer in a monad transformer stack.

Note, that if the HasWriter instance is based on HasState, then it is more efficient to apply Lift to the underlying state capability. E.g. you should favour

deriving (HasWriter tag w) via
  WriterLog (Lift (SomeTrans (MonadState SomeStateMonad)))

over

deriving (HasWriter tag w) via
  Lift (SomeTrans (WriterLog (MonadState SomeStateMonad)))
Instance details

Defined in Capability.Writer.Discouraged

Methods

writer_ :: Proxy# tag -> (a, w) -> Lift (t m) a Source #

tell_ :: Proxy# tag -> w -> Lift (t m) () Source #

listen_ :: Proxy# tag -> Lift (t m) a -> Lift (t m) (a, w) Source #

pass_ :: Proxy# tag -> Lift (t m) (a, w -> w) -> Lift (t m) a Source #

writer :: forall tag w m a. HasWriter tag w m => (a, w) -> m a Source #

writer @tag (a, w) lifts a pure writer action (a, w) to a monadic action in an arbitrary monad m with capability HasWriter.

Appends w to the output of the writer capability tag and returns the value a.

tell :: forall tag w m. HasWriter tag w m => w -> m () Source #

tell @tag w appends w to the output of the writer capability tag.

listen :: forall tag w m a. HasWriter tag w m => m a -> m (a, w) Source #

listen @tag m executes the action m and returns the output of m in the writer capability tag along with result of m. Appends the output of m to the output of the writer capability tag.

pass :: forall tag w m a. HasWriter tag w m => m (a, w -> w) -> m a Source #

pass @tag m executes the action m. Assuming m returns (a, f) and appends w to the output of the writer capability tag. pass @tag m instead appends w' = f w to the output and returns a.

Strategies

newtype WriterLog m a Source #

Constructors

WriterLog (m a) 
Instances
(Monoid w, HasState tag w m) => HasWriter (tag :: k) w (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Methods

writer_ :: Proxy# tag -> (a, w) -> WriterLog m a Source #

tell_ :: Proxy# tag -> w -> WriterLog m () Source #

listen_ :: Proxy# tag -> WriterLog m a -> WriterLog m (a, w) Source #

pass_ :: Proxy# tag -> WriterLog m (a, w -> w) -> WriterLog m a Source #

Monad m => Monad (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Methods

(>>=) :: WriterLog m a -> (a -> WriterLog m b) -> WriterLog m b #

(>>) :: WriterLog m a -> WriterLog m b -> WriterLog m b #

return :: a -> WriterLog m a #

fail :: String -> WriterLog m a #

Functor m => Functor (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Methods

fmap :: (a -> b) -> WriterLog m a -> WriterLog m b #

(<$) :: a -> WriterLog m b -> WriterLog m a #

Applicative m => Applicative (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Methods

pure :: a -> WriterLog m a #

(<*>) :: WriterLog m (a -> b) -> WriterLog m a -> WriterLog m b #

liftA2 :: (a -> b -> c) -> WriterLog m a -> WriterLog m b -> WriterLog m c #

(*>) :: WriterLog m a -> WriterLog m b -> WriterLog m b #

(<*) :: WriterLog m a -> WriterLog m b -> WriterLog m a #

MonadIO m => MonadIO (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Methods

liftIO :: IO a -> WriterLog m a #

PrimMonad m => PrimMonad (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Associated Types

type PrimState (WriterLog m) :: Type #

Methods

primitive :: (State# (PrimState (WriterLog m)) -> (#State# (PrimState (WriterLog m)), a#)) -> WriterLog m a #

type PrimState (WriterLog m) Source # 
Instance details

Defined in Capability.Writer

Modifiers