【问题标题】:Execute monadic code from newly created monad从新创建的 monad 执行 monadic 代码
【发布时间】:2013-11-03 14:42:11
【问题描述】:

我目前有两个共享相同类型的 monad,实现类似于 State monad:

newtype FooRead  a = FooRead  { runFooRead  :: Context -> (a,Context) }
newtype FooWrite a = FooWrite { runFooWrite :: Context -> (a,Context) }

它们之间的区别在于,第一个只允许读取上下文(bind 不会改变它),而第二个也允许编辑上下文。

然后有函数使用FooRead 中的上下文来计算一些值而不改变上下文的状态:

getVal :: FooRead a
getVal = do x <- ...
            return x

现在我想从 writer monad 的代码中执行这些读取函数之一:

writeFunc :: FooWrite ()
writeFunc = do x <- liftVal getVal
            ...

其中liftVal :: FooRead a -&gt; FooWrite a 是一个函数,它提取FooRead 函数返回的值并将其滚动到FooWrite monad 中。这一切都很好。

但是,我想不出一种方法将上面的getVal 的执行从我的FooWrite monad 滚动到上下文中。通过上述实现,getVal 将在 monad 的空实例中运行。

我可以弄清楚如何使用FooWrite 上下文构造FooRead 实例

lower :: FooWrite a -> FooRead a

基本上我想将我的作者降级为读者,在阅读器中执行代码,然后将其重新提升为作者。

但不知道如何在这个 monad 中实际执行代码?

【问题讨论】:

  • 你需要创建monad trnsformer FooReadT(或FooWriteT)并扩展你的monad FooWrite(或FooRead

标签: haskell monads state-monad lifting


【解决方案1】:

这就是我将如何实现它。首先,如果你想让WriterReader 更强大,那么我们需要一个函数

liftReader :: FooReader a -> FooWriter a
liftReader (FooReader a) = FooWriter a

这是可行的,因为它们在结构上是等效的,并且它们的 monad 实例应该是同构的。

那么我们就可以了

t :: FooWriter Int
t = liftReader getVal

如果你想走另一条路,这很容易

liftWriter :: FooWriter a -> FooReader a
liftWriter (FooWriter a) = FooReader a

现在我们可以将这些类型相互提升这一事实让你认为它们在某种程度上是等价的。事实上它们是,你基本上有

import Control.Monad.State
newtype FooReader s a = FooReader (State s a)
newtype FooWriter s a = FooWriter (State s a)

State 提供getput,类似于您的getValwriteFunc

【讨论】:

  • 嗨jozefg。我已经想出了如何实现liftWriterliftReader 之类的东西(在我的示例中它们大致相当于lowerliftVal)。问题是我想通过从我的FooWriter 传输上下文来从我的FooWriter 执行FooReadergetVal 这样的单子代码。运行 do a &lt;- liftReader getVal 之类的东西仍然会在空上下文的情况下运行 getVal。相反,我想使用来自FooWriter 的上下文,它用liftReader 调用它。
  • @jlicht 我在这里很困惑,你能澄清一下你所说的上下文是什么意思吗?使用liftWriter/Reader,您可以访问周围 monad 的所有上下文,例如状态。
  • 对不起,我误解了你的回答。我认为您的liftWriterliftReader 的工作方式与我实施的方式相同。我又试了一次,它似乎奏效了。谢谢,接受!
  • @jozefg 上面的 liftReader 很好,但是 liftWriter 返回一个 FooReader 可能能够更改上下文。我建议改为liftWriter (FooWriter a) = FooReader $ \s -&gt; (fst (a s), s)
  • @ØrjanJohansen 我知道,这是故意的。 OP 指定它在相同的上下文中运行,我想展示它与State 的同构
猜你喜欢
  • 1970-01-01
  • 2012-03-20
  • 2016-04-28
  • 2014-10-16
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
相关资源
最近更新 更多