Skip to content

Provide instances for MTL interop #18

@andremarianiello

Description

@andremarianiello

Some libraries, like lens, provide functions that are meant for use in MTL transformer stacks. Example:

http://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Setter.html#g:5

If Eff had an instance for MonadState, then I could use those Lens functions without having to rewrite them using the put and get from Control.Monad.Freer.State - it would happen automatically.

I have spent a number of days on this, but my instance manipulation skills are not the greatest, so I ended up with something like this:

instance MTL.MonadState s (Eff (State s ': effs)) where
get = get
put = put

instance {-# OVERLAPPABLE #-} MTL.MonadState s (Eff effs) => MTL.MonadState s (Eff (eff ': effs)) where
get = MTL.get
put = MTL.put

-- single actions that uses MTL and Eff values together without wrapping/unwrapping newtypes
action :: Eff (State Bool ': effs) ()
action = do
b <- MTL.get
put $ not b

ranAction :: Eff effs ((), Bool)
ranAction = runState True action

I also tried a solution involves defining an instance for a newtype wrapping Eff and using the constraints library to unsafely deduce MonadState s (Eff effs) from Member (State s) effs, but I had to use explicit TypeApplication to get it to work. I can post the code for that if you think that avenue is more likely where you would want to go with this.

A third possibility would be using something from the reflection package to provide the instance at runtime, but I haven't explored that.

I have only been playing around with

TL;DR: I don't know the best way to do this, but I think this library can provide something helpful for this use case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions