ReaderT IORef 的缩放实例
Zoom instance for ReaderT IORef
我是 lens 的新手,无法为此类型实现 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 实例正常工作吗?谢谢!
我的建议是:
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
。所以需要直接使用函数application来申请l
注意:您需要谨慎处理此实现。 IORef
不是原子的,除非你在纯函数上使用 atomicModifyIORef
(这在 zoom
中似乎不可能)。因此,将 MVar
与 takeMVar
和 putMVar
一起使用可能是有意义的,以确保在多线程环境中 运行 时您的计算正常工作。
我是 lens 的新手,无法为此类型实现 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 实例正常工作吗?谢谢!
我的建议是:
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
。所以需要直接使用函数application来申请l
注意:您需要谨慎处理此实现。 IORef
不是原子的,除非你在纯函数上使用 atomicModifyIORef
(这在 zoom
中似乎不可能)。因此,将 MVar
与 takeMVar
和 putMVar
一起使用可能是有意义的,以确保在多线程环境中 运行 时您的计算正常工作。