ReaderT IORef的缩放实例

时间:2018-02-10 03:46:50

标签: haskell monad-transformers lens ioref

我是镜头新手,无法为此类型实施Zoom实例:

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

我一直试图使用镜头底座制作新的IORef,在该子状态下运行ReaderT,然后抓住更改的子状态并将其替换为主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似乎与普通镜头有所不同,因此^..~无法使用它进行编译,我会收到如下错误:

    • 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

任何人都可以帮我让这个Zoom实例正常工作吗?谢谢!

1 个答案:

答案 0 :(得分:1)

我的建议是:

AsEnumerable()

您使用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

注意:您需要对此实现有点小心。除非您在纯函数上使用lIORef中似乎不可能),否则atomicModifyIORef必须是原子的。因此,将zoomMVartakeMVar结合使用可能有意义,以确保您的计算在多线程环境中运行时能正常工作。