thanks again for the help!
I'm making extensive use of the E. Kmett's Lens library, to avoid X/Y problems I'll explain a bit of context.
I'm working on an extensible text editor and want to provide extension writers with a monad DSL, an Alteration
is a monad transformer stack with a StateT over the Store
type, which basically stores the whole text editor. Inside the Store
is an Editor
which has Buffer
s. Users can specify an Alteration
to act over the whole store, but to simplify things I also provide a BufAction
which operates over just a single buffer.
I was planning on implementing this by using a helper called bufDo
which runs a BufAction
over each Buffer
, and a focusDo
which runs a BufAction
on the 'focused' Buffer
. Here's some context:
data Store = Store
{ _event :: [Event]
, _editor :: E.Editor
, _extState :: Map TypeRep Ext
} deriving (Show)
data Editor = Editor {
_buffers :: [Buffer]
, _focused :: Int
, _exiting :: Bool
} deriving Show
data Buffer = Buffer
{ _text :: T.Text
, _bufExts :: Map TypeRep Ext
, _attrs :: [IAttr]
}
newtype Alteration a = Alteration
{ runAlt :: StateT Store IO a
} deriving (Functor, Applicative, Monad, MonadState Store, MonadIO)
newtype BufAction a = BufAction
{ runBufAction::StateT Buffer IO a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadIO)
Here's my proposed implementations for bufDo
and focusDo
:
bufDo :: ???
bufDo = zoom (buffers.traverse)
-- focusedBuf is a Lens' over the focused buffer (I just 'force' the traversal using ^?! in case you're wondering)
focusDo :: ???
focusDo = zoom focusedBuf
This makes sense in my head and gets close to type-checking, but when I try to add a type for them I get a bit confused, ghc suggests a few things and I ended up with this, which is far from elegant:
bufDo :: (Applicative (Zoomed BufAction ()), Zoom BufAction Alteration Buffer Store) => BufAction () -> Alteration ()
focusDo :: (Functor (Zoomed BufAction ()), Zoom BufAction Alteration Buffer Store) => BufAction () -> Alteration ()
Which makes ghc happy for those definitions, but when I try to actually use either of them I get these errors:
- No instance for (Functor (Zoomed BufAction ()))
arising from a use of ‘focusDo’
- No instance for (Applicative (Zoomed BufAction ()))
arising from a use of ‘bufDo’
Looking around it seems like I may need to specify an instance for Zoom, but I'm not sure quite how to do that.
Anyone have ideas? I'd also love it if you could explain why I need a Zoom instance (if that's the case).
Cheers!