Haskell 缩放单子堆栈维护上下文
是时候问我每周的镜头问题了 我有一个单子堆栈:Haskell 缩放单子堆栈维护上下文,haskell,haskell-lens,lenses,Haskell,Haskell Lens,Lenses,是时候问我每周的镜头问题了 我有一个单子堆栈: 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
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]
}
我使用编辑器
类型生成编辑器所依赖的hasdeditor
类型类
一个编辑器
有许多缓冲区
s;我已经为一个动作定义了另一个monad堆栈类型,该动作在一个特定的缓冲区上运行(ab
);唯一的区别是StateT位于缓冲区上:
newtype BufAction a = BufAction
{ runBufAct::StateT Buffer (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadReader Hooks, MonadIO)
要运行buction
I使用zoom(editor.buffers.ix选中)
将StateT缩放到特定的缓冲区;但问题是,现在在bupartion
中,我不能再使用任何通过editor
操作或需要hasdeditor
的镜头
理想情况下,所有动作
都在动作
内运行,而动作
不能在动作
内运行。在这种情况下,buction
需要完整的ActionState
,但也需要对特定缓冲区的引用才能运行;而Action
只需要ActionState
;因此,buaction
是一个限制性更强的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对此感到窒息;它不能处理新类型中的存在和约束
我把它换成了数据
类型;但是我失去了一般化的newtypedering,需要实现所有这些派生
手动子句;我真的不想这么做
我还尝试使用类型别名;这意味着我不需要派生类型类,但因为我还嵌入了动作
在其他数据类型中,我遇到了错误;例如,由于我在这里使用了操作
:
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使用函数依赖项
我真的被这个卡住了,我需要一只手
谢谢你看!我真的很感谢你的帮助 看来这就是你想对我做的事。关于操作中可接受的状态类型的约束将在使用操作的定义中指定,而不是操作本身。然后,您将能够使用镜头软件包中的缩放
功能,例如,在编辑器中聚焦不同的缓冲区
{-# 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
看起来这就是你想对我做的。关于操作中可接受的状态类型的约束将在使用操作的定义中指定,而不是操作本身。然后,您将能够使用镜头软件包中的缩放
功能,例如,在编辑器中聚焦不同的缓冲区
{-# 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
你的问题有点不清楚。你说“所有动作
都在动作
中工作,而动作
不能在动作
中运行”—当动作的状态小于动作
的状态时,这是如何工作的?当然应该是另一种情况吗?对不起,不清楚;我会尽量解释得更清楚一点。正确,BUP使用的状态比操作
更小,但与其说是“更小的状态”,不如说是具有“更多信息”的状态。我们可以将buaction
可用的状态看作(ActionState,BufId)
;基本上,整个ActionState
都是可用的(就像Action
),但我们也有一些信息可以让我们关注特定的缓冲区。因此,在ActionState
上运行的任何Action
都应该在buaction
中仍然可用;但是buvity
s需要BufId
上下文,不能在操作中运行。更清楚了吗?这当然意味着我们必须改变这个状态,这个状态实际上包含了更大的状态;但这就是hasdeditor
和HasBuffer
约束所指的内容<代码>操作
应仅在具有HasEditor
的状态上运行;而buction
应该用hasdeditor
和HasBuffer
运行在state上,所以它的限制性更大。所以如果我理解正确的话,你有type Buffer=(ActionState,BufId)
,你想用state Buffer
组成state ActionState
?“缩放”有什么问题吗?@BenjaminHodgson,实际上应该可以;但问题在于指定monad堆栈的实际类型;如果我想让我的Action
Monad堆栈同时在bupartion
堆栈和Action
堆栈中工作,我需要堆栈足够通用;i、 例如newtype动作a=forall s。hasdeditor s=>操作(StateT s IO a)
;但是你的新类型中不能有存在主义;您可以为数据类型执行此操作,但随后我将失去GeneralizedNewType派生,必须为自己编写实例(Functor、Applicative、Monad、MonadState s、MonadIO);我能做到;但我不想。你的问题有点不清楚。你说“所有动作
都在动作
中工作,而动作
不能在动作
中运行”—当动作的状态小于动作
的状态时,这是如何工作的?当然应该是另一种情况吗?对不起,不清楚;我会尽量解释得更清楚一点。正确,BUP使用的状态比操作
更小,但与其说是“更小的状态”,不如说是具有“更多信息”的状态。我们可以将buaction
可用的状态看作(ActionState,BufId)
;基本上整个ActionState
都是可用的(就像Action
),但是我们有一些信息可以让我们将特定的缓冲区作为