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堆栈类型,该动作在一个特定的缓冲区上运行(a
b
);唯一的区别是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
),但是我们有一些信息可以让我们将特定的缓冲区作为