我每周镜片问题的时间;
我有一个monad堆栈:
newtype Action a = Action
{ runAct :: StateT ActionState (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState ActionState, MonadReader Hooks, MonadIO)
data ActionState = ActionState
{ _ed :: Editor
, _asyncs :: [AsyncAction]
}
我在Editor
类型上使用了makeClassy
来生成我的编辑镜头所依赖的HasEditor
类型类。
Editor
有很多Buffer
个;我为一个特定缓冲区(BufAction
)上的动作定义了另一个monad堆栈类型;唯一的区别是StateT超过Buffer
:
newtype BufAction a = BufAction
{ runBufAct::StateT Buffer (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadReader Hooks, MonadIO)
运行BufAction
我使用zoom (editor.buffers.ix selected)
将StateT缩放到特定缓冲区;但问题是,现在在BufAction
内,我无法再使用任何在editor
或HasEditor
上运行的镜头。
理想情况下,所有Action
都在BufAction
内运行而不会提升,而BufAction
无法在Action
内运行。在这种情况下,BufAction
将需要完整的ActionState
,但也需要对特定缓冲区的引用才能运行;而Action
只需要ActionState
;所以BufAction
是一个限制性较强的Monad,Action
应该嵌入其中。
所以我想要某种类型的这种类型:
newtype Action a = forall s. HasEditor s => Action
{ runAct :: StateT s (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState s, MonadReader Hooks, MonadIO)
然而GHC对此嗤之以鼻;它无法处理新类型中的存在和约束;
我将其切换为data
类型;但后来我失去了GeneralizedNewtypeDeriving并需要实现所有这些派生
手动条款;我真的不愿意这样做。
我也尝试过使用类型别名;这意味着我不需要派生类型类,但因为我也嵌入了动作
在其他数据类型中,我遇到了错误;例如,因为我在这里使用Action
:
data ActionState = ActionState
{ _ed :: Editor
, _asyncs :: [Async (Action ())]
, _hooks :: Hooks
, _nextHook :: Int
}
我遇到了:
• Illegal polymorphic type: Action ()
GHC doesn't yet support impredicative polymorphism
• In the definition of data constructor ‘ActionState’
In the data type declaration for ‘ActionState’
采取不同的机智;我也尝试过实现一个灵活的MonadState实例:
instance (HasEditor s, HasBuffer s) => (MonadState s) BufAction where
但得到:
• Illegal instance declaration for ‘MonadState s BufAction’
The coverage condition fails in class ‘MonadState’
for functional dependency: ‘m -> s’
Reason: lhs type ‘BufAction’ does not determine rhs type ‘s’
Un-determined variable: s
• In the instance declaration for ‘(MonadState s) BufAction’
因为MonadState使用功能依赖...
真的坚持这个,我可以用一只手!
谢谢你看看!我非常感谢你的帮助!
答案 0 :(得分:0)
看起来这就是你要对我做的事情。关于Action中可接受哪种状态的约束将在使用Action而不是action本身的定义上指定。然后,您就可以使用镜头包中的zoom
功能,专注于Buffer
中的不同Editor
。
{-# Language TemplateHaskell #-}
{-# Language GeneralizedNewtypeDeriving #-}
{-# Language MultiParamTypeClasses #-}
{-# Language FlexibleInstances #-}
{-# Language TypeFamilies #-}
{-# Language UndecidableInstances #-} -- for the Zoomed type instance
module Demo where
import Control.Monad.State
import Control.Monad.Reader
import Control.Lens
data Hooks
data SomeState = SomeState
{ _thing1, _thing2 :: Int }
makeLenses ''SomeState
newtype Action s a = Action
{ runAct :: StateT s (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState s)
instance Zoom (Action a) (Action s) a s where
zoom l (Action m) = Action (zoom l m)
type instance Zoomed (Action s) = Zoomed (StateT s (ReaderT Hooks IO))
example :: Action Int a -> Action SomeState a
example = zoom thing1