我是个镜头新手,在实现这个类型的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 vl似乎与普通镜头不同,所以^.和.~无法使用它进行编译,我得到的错误如下:
• 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实例正常工作吗?谢谢!
发布于 2018-02-11 02:22:11
我的建议是:
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与takeMVar和putMVar一起使用可能更有意义,以确保在多线程环境中运行时计算工作正常。
https://stackoverflow.com/questions/48717004
复制相似问题