首页 文章

镜头:缩放newtype

提问于
浏览
4

我有兴趣为我的monad变换器堆栈获取缩放功能,其定义方式如下:

newtype Awesome a = Awesome (StateT AwesomeState (ExceptT B.ByteString IO) a)
  deriving (Functor, Applicative, Monad
           , MonadIO, MonadError B.ByteString
           , MonadState AwesomeState)

我的AwesomeState是深度嵌套的记录,因此使用zoom将极大地帮助我更新一些字段 . 但问题是缩放对我的newtype来说不是开箱即用的 .

Couldn't match type ‘Control.Lens.Internal.Zoom.Zoomed Awesome’ 
with ‘Control.Lens.Internal.Zoom.Zoomed m0’

我找到了一个如何制作Zoom的自定义newtype RWST实例的例子,但是试图让它适应我的newtype却没有给我带来任何结果

可在此处找到RWST示例:http://lpaste.net/87737

有没有办法可以开始使用我的monad变换器堆栈进行缩放?为了达到这个目的,我需要做些什么?如果我应该像在RWST示例中那样实现Zoomed / Zoom,那么我需要一个如何做到这一点的指针,因为我试过并且没有这样做 .

1 回答

  • 3

    我建议明确 Awesome 的状态:

    {-# LANGUAGE TemplateHaskell, GeneralizedNewtypeDeriving, TypeFamilies,
        FlexibleInstances, FunctionalDependencies #-}
    import Control.Applicative
    import Control.Monad.Error
    import Control.Monad.State
    import Control.Lens
    import Control.Lens.Zoom
    import Control.Lens.Internal.Zoom
    
    data AwesomeState = AwesomeState
        { _someRecord :: String
        -- ...
        }
    
    $(makeLenses ''AwesomeState)
    
    newtype Awesome s a = Awesome (StateT s (ErrorT String IO) a)
      deriving ( Functor, Applicative, Monad
               , MonadIO, MonadError String
               , MonadState s)
    

    然后你可以为它定义 Zoom 实例,如下所示:

    type instance Zoomed (Awesome s) = Focusing (ErrorT String IO)
    
    instance Zoom (Awesome s) (Awesome t) s t where
        zoom l (Awesome m) = Awesome (zoom l m)
    

    然后你会有

    zoom someRecord :: Awesome String a -> Awesome AwesomeState a
    

相关问题