monads-tf:MonadState 的 MonadReader 实例
考虑下一个例子。我有一个单子 MyM
它只是一个 StateT
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.State
import Control.Monad.Reader
type MyS = Int
type MyM = StateT MyS
通常 MyM
用于读取和写入 MyS
状态,所以我有类似下一个的功能:
f1 :: (MonadState m, StateType m ~ MyS) => m ()
f1 = modify (+1)
但有时我只需要读取 MyS
,所以我想要 MonadReader
上下文而不是 MonadState
:
f2 :: (MonadReader m, EnvType m ~ MyS) => m Int
f2 = liftM (+1) ask
而且我想写一些类似的东西:
f3 :: (MonadState m, StateType m ~ MyS) => m Int
f3 = f1 >> f2
所以基本上我需要每一个MonadState
实例也是具有相应系列类型的 MonadReader
实例。类似
instance MonadState m => MonadReader where
type EnvType m = StateType m
...
但我找不到如何进行类型检查的方法。是否可以表达 MonadState
和 MonadReader
之间的关系?
谢谢。
Consider the next example. I have a monad MyM
that is just a StateT
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.State
import Control.Monad.Reader
type MyS = Int
type MyM = StateT MyS
Usually MyM
is used for reading and writing MyS
state, so I have functions like the next:
f1 :: (MonadState m, StateType m ~ MyS) => m ()
f1 = modify (+1)
But sometimes I need just to read MyS
, so I want MonadReader
context instead of MonadState
:
f2 :: (MonadReader m, EnvType m ~ MyS) => m Int
f2 = liftM (+1) ask
And I want to write something like:
f3 :: (MonadState m, StateType m ~ MyS) => m Int
f3 = f1 >> f2
So basically I need every MonadState
instance to be MonadReader
instance too with the correspondent family type. Something like
instance MonadState m => MonadReader where
type EnvType m = StateType m
...
But I can't find the way how to make it type check. Is it possible to express such the relation between MonadState
and MonadReader
?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
听起来您想要的本质上是
ask
与get
具有相同的效果。我忍不住想知道为什么在这种情况下你不只使用get
:)如果你的目标是编写根据可用内容读取状态或环境的代码,那么你有询问您打算如何处理,例如
ReaderT r (StateT sm) a
,两者都有。因此,您不能这样做:因为您会与现有实例发生冲突。但是,您可以这样做:
然后,如果您有一个像
f2
这样的多态读取器值,您可以使用unRS
从其中提取MonadState
。如果您想使用一些更狡猾的扩展,请尝试使用RankNTypes
:然后您可以执行
useStateAsEnv (liftM (+1) Ask)
并获取MonadState< /代码> 值。然而,我还没有彻底研究过这在实践中有多有用——为所有 m 生成
类型的值。 MonadReader m => m a
,您几乎只能使用ask
、local
和 monadic 函数。这是一个类似的,不太通用但可能更有用的东西,使用标准转换器:
编辑:稍后考虑这一点,您可能可以将其推广到任何带有
lift 的状态单子转换器。 runReaderT 阅读器 =<< get
,但该类型开始变得相当笨拙:这是上述内容的概括,但实际上可能并不是一个有用的类型。
It sounds like what you want is essentially
ask
to have the same effect asget
. I can't help but wonder why you don't just useget
in that case :)If your aim is to write code that either reads the state or the env depending on what is available, you have to ask what you plan to do with, say,
ReaderT r (StateT s m) a
, where you have both. For that reason, you can't just do:because you'll conflict with existing instances. You can, however, do:
Then if you have a polymorphic reader value like
f2
, you can pull aMonadState
out of it withunRS
. If you want to use some more devious extensions, try this withRankNTypes
:Then you can do
useStateAsEnv (liftM (+1) ask)
and get aMonadState
value. I haven't thoroughly investigated how useful this is in practice, however – to produce a value of typeforall m. MonadReader m => m a
, you can pretty much only useask
,local
, and monadic functions.Here's a similar, less general but probably more useful thing, using standard transformers:
Edit: thinking about this later you could probably generalise this to any state monad transformer with
lift . runReaderT reader =<< get
, but the type starts to be rather unwieldy:which is a generalisation of the above but may not actually be a useful one.