1

I'm new to lens and having trouble implementing the Zoom instance for this type:

newtype MyStateT s m a = MyStateT
    { unMyStateT :: ReaderT (IORef s) m a
    } deriving (Functor, Applicative, Monad, MonadIO)

instance (MonadIO m) => MonadState s (MyStateT s m) where
    get = MyStateT $ ReaderT $ liftIO . readIORef
    put x = MyStateT $ ReaderT $ \ref -> liftIO $ writeIORef ref x

I've been trying to make a new IORef with the lens substate, run the ReaderT on that substate, and then grab the changed substate and replace it in the main IORef:

type instance Zoomed (MyStateT s m) = Focusing m
instance (Monad m) => Zoom (MyStateT s m) (MyStateT t m) s t where
    zoom l (MyStateT r) =
        MyStateT $ ReaderT $ \ref -> do
            s <- liftIO $ readIORef ref
            ref' <- liftIO $ newIORef $ s ^. l
            let v = runReader r ref'
            subS' <- liftIO $ readIORef ref'
            let s' = s & l .~ subS'
            liftIO $ writeIORef ref s'
            return v

l seems to be different from a normal lens so ^. and .~ doesn't compile with it and I get errors like this:

    • Couldn't match type ‘Focusing m c t’ with ‘Const s t’
  Expected type: Getting s t s
    Actual type: LensLike' (Zoomed (MyStateT s m) c) t s
   • Couldn't match type ‘Focusing m c t’ with ‘Identity t’
  Expected type: ASetter t t s s
    Actual type: LensLike' (Zoomed (MyStateT s m) c) t s

Can anyone help me get this Zoom instance to work properly? Thanks!

4

1 回答 1

1

我的建议是:

type instance Zoomed (MyStateT s m) = Focusing m

instance (MonadIO m) => Zoom (MyStateT s m) (MyStateT t m) s t where
    zoom l (MyStateT r) =
        MyStateT $ ReaderT $ \ref -> do
            s <- liftIO $ readIORef ref
            (v', s') <- unfocusing . flip l s $ \t -> Focusing $ do
                ref' <- liftIO (newIORef t)
                v <- runReaderT r ref'
                t' <- liftIO (readIORef ref')
                return (v, t')
            liftIO $ writeIORef ref s'
            return v'
    {-# INLINE zoom #-}

您遇到的问题(^.)(.~)它们适用于Lens,它在函子中是多态的。但是这里的函子是固定的Zoomed (MyState s m) c,即Focusing m c。所以你需要l直接使用函数应用程序来申请。

注意:你需要小心这个实现。IORef不是原子的,除非您atomicModifyIORef在纯函数上使用(这在 中似乎不可能zoom)。MVar因此,使用withtakeMVar和代替可能是有意义的putMVar,以确保您的计算在多线程环境中运行时正常工作。

于 2018-02-10T18:22:11.493 回答