缩放 monad 堆栈维护上下文
Zoom monad stack maintaining context
我的每周镜头问题时间到了;
我有一个 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
;我已经为作用于特定缓冲区的操作定义了另一个 monad 堆栈类型 (a BufAction
);唯一的区别是 StateT 在 Buffer
:
newtype BufAction a = BufAction
{ runBufAct::StateT Buffer (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadReader Hooks, MonadIO)
到 运行 a BufAction
我使用 zoom (editor.buffers.ix selected)
将 StateT 缩放到特定缓冲区;但问题是,现在在 BufAction
内,我不能再使用任何超过 editor
或需要 HasEditor
.
的镜头
理想情况下,BufAction
内的所有 Action
s 运行 都没有提升,而 BufAction
s 不能 运行 在 Action
内。在这种情况下 BufAction
将需要完整的 ActionState
,而且还需要对特定缓冲区的引用才能 运行;而 Action
只需要 ActionState
;所以 BufAction
是一个更严格的 Monad 并且 Action
s 应该可以嵌入其中。
大概我想要这样的类型:
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 并且需要实现所有这些派生
手动条款;我真的不想这样做。
我也试过使用类型别名;这意味着我不需要派生类型类,但因为我还嵌入了 Actions
在其他数据类型中,我 运行 出错;例如,因为我在这里使用 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 使用函数依赖...
真的坚持这个,我可以用一只手!
感谢观看!非常感谢您的帮助!
看来这就是你想对我做的。关于 Action 中可接受的状态类型的约束将在使用 Action 的定义中指定,而不是 Action 本身。然后,您将能够使用镜头包中的 zoom
功能来聚焦 Editor
中的不同 Buffer
,例如。
{-# 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
我的每周镜头问题时间到了;
我有一个 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
;我已经为作用于特定缓冲区的操作定义了另一个 monad 堆栈类型 (a BufAction
);唯一的区别是 StateT 在 Buffer
:
newtype BufAction a = BufAction
{ runBufAct::StateT Buffer (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadReader Hooks, MonadIO)
到 运行 a BufAction
我使用 zoom (editor.buffers.ix selected)
将 StateT 缩放到特定缓冲区;但问题是,现在在 BufAction
内,我不能再使用任何超过 editor
或需要 HasEditor
.
理想情况下,BufAction
内的所有 Action
s 运行 都没有提升,而 BufAction
s 不能 运行 在 Action
内。在这种情况下 BufAction
将需要完整的 ActionState
,而且还需要对特定缓冲区的引用才能 运行;而 Action
只需要 ActionState
;所以 BufAction
是一个更严格的 Monad 并且 Action
s 应该可以嵌入其中。
大概我想要这样的类型:
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 并且需要实现所有这些派生
手动条款;我真的不想这样做。
我也试过使用类型别名;这意味着我不需要派生类型类,但因为我还嵌入了 Actions
在其他数据类型中,我 运行 出错;例如,因为我在这里使用 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 使用函数依赖...
真的坚持这个,我可以用一只手!
感谢观看!非常感谢您的帮助!
看来这就是你想对我做的。关于 Action 中可接受的状态类型的约束将在使用 Action 的定义中指定,而不是 Action 本身。然后,您将能够使用镜头包中的 zoom
功能来聚焦 Editor
中的不同 Buffer
,例如。
{-# 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