再次感谢您的帮助!
我大量使用E. Kmett的镜头库,以避免X / Y问题我会解释一些背景。
我正在使用可扩展的文本编辑器,并希望为扩展编写器提供monad DSL,Alteration
是一个monad转换器堆栈,其状态为Store
类型的状态,基本上存储整个文本编辑器。 Store
内的Editor
内有Buffer
个。用户可以指定Alteration
来对整个商店进行操作,但为了简化操作,我还提供了BufAction
,它只能在一个缓冲区上运行。
我计划通过使用名为bufDo
的帮助程序来实现此功能,该帮助程序在BufAction
上运行Buffer
,并运行focusDo
BufAction
关注焦点' Buffer
。这里有一些背景信息:
data Store = Store
{ _event :: [Event]
, _editor :: E.Editor
, _extState :: Map TypeRep Ext
} deriving (Show)
data Editor = Editor {
_buffers :: [Buffer]
, _focused :: Int
, _exiting :: Bool
} deriving Show
data Buffer = Buffer
{ _text :: T.Text
, _bufExts :: Map TypeRep Ext
, _attrs :: [IAttr]
}
newtype Alteration a = Alteration
{ runAlt :: StateT Store IO a
} deriving (Functor, Applicative, Monad, MonadState Store, MonadIO)
newtype BufAction a = BufAction
{ runBufAction::StateT Buffer IO a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadIO)
以下是bufDo
和focusDo
的建议实施方式:
bufDo :: ???
bufDo = zoom (buffers.traverse)
-- focusedBuf is a Lens' over the focused buffer (I just 'force' the traversal using ^?! in case you're wondering)
focusDo :: ???
focusDo = zoom focusedBuf
这在我的脑海中是有意义的并且接近类型检查,但是当我尝试为它们添加类型时我感到有些困惑,ghc建议了一些事情,我最终得到了这个,这远非优雅:
bufDo :: (Applicative (Zoomed BufAction ()), Zoom BufAction Alteration Buffer Store) => BufAction () -> Alteration ()
focusDo :: (Functor (Zoomed BufAction ()), Zoom BufAction Alteration Buffer Store) => BufAction () -> Alteration ()
这让ghc对这些定义感到满意,但是当我尝试使用其中任何一个时,我都会遇到这些错误:
- No instance for (Functor (Zoomed BufAction ()))
arising from a use of ‘focusDo’
- No instance for (Applicative (Zoomed BufAction ()))
arising from a use of ‘bufDo’
环顾四周似乎我可能需要为Zoom指定一个实例,但我不确定如何做到这一点。
有人有想法吗?如果你能解释为什么我需要一个Zoom实例(如果是这样的话),我也会喜欢它。
干杯!
答案 0 :(得分:3)
除了答案@danidiaz。
基本上,您可以通过这种方式避免Zoom
实例:
bufDo :: BufAction () -> Alteration ()
bufDo = Alteration . zoom (editor . buffers . traverse) . runBufAction
答案 1 :(得分:2)
似乎有一个Zoomed
类型系列用于指定什么样的"效果"当我们放大时我们会有。在某些情况下,monad变换器的Zoomed
类型实例似乎搭载在基础monad的Zoomed
上,例如
type Zoomed (ReaderT * e m) = Zoomed m
鉴于Alteration
和BufAction
只是状态转换器的新类型,也许我们也可以这样做:
{-# language TypeFamilies #-}
{-# language UndecidableInstances #-}
{-# language MultiParamTypeClasses #-}
type instance Zoomed BufAction = Zoomed (StateT Buffer IO)
然后我们必须提供Zoom
实例。 Zoom
是一个多参数类型类,四个参数似乎是原始monad ,缩小monad ,原始状态,< em>缩小状态:
instance Zoom BufAction Alteration Buffer Store where
zoom f (BufAction a) = Alteration (zoom f a)
我们只需展开BufAction
,使用基础monad进行缩放,然后换行为Alteration
。
这个基本测试类型检查:
foo :: Alteration ()
foo = zoom (editor.buffers.traversed) (return () :: BufAction ())
我相信您可以避免定义Zoom
实例并具有专用zoomBufActionToAlteration
函数
zoomBufActionToAlteration :: LensLike' (Zoomed (StateT Buffer IO) a) Store Buffer
-> BufAction a
-> Alteration a
zoomBufActionToAlteration f (BufAction a) = Alteration (zoom f a)
但是如果你有很多不同的可缩放的东西,记住每个缩放功能的名称可能是一件苦差事。这是类型类可以帮助的地方。