【问题标题】:Is there any significant difference between StateT over Reader and ReaderT over State?StateT over Reader 和 ReaderT over State 之间有什么显着区别吗?
【发布时间】:2023-03-30 01:34:02
【问题描述】:

当我设计我的编程模型时,我总是纠结于哪种方法更好:

type MyMonad1 = StateT MyState (Reader Env)
type MyMonad2 = ReaderT Env (State MyState)

在使用一个 monad 和另一个之间有什么好处和权衡?这有关系吗?性能怎么样?

【问题讨论】:

  • 我不是 Monad Transformers 方面的专家,但据我所知,这并不重要。模新类型,MyMonad1 aMyState -> Env -> (a, MyState) 一样,而MyMonad2 aEnv -> MyState -> (a, MyState),所以唯一的区别是参数顺序。
  • 这个问题是专门针对ReaderTStateT,还是一般来说是关于如何选择堆栈中的transformer的顺序?
  • 具体说这两个

标签: performance haskell monads state-monad reader-monad


【解决方案1】:

在一般情况下,monad 转换器的不同排序会导致不同的行为,但正如 cmets 中所指出的,对于“状态”和“读者”这两个排序,我们有以下同构直到新类型:

StateT MyState (Reader Env) a  ~  MyState -> Env -> (a, MyState)
ReaderT Env (State MyState) a  ~  Env -> MyState -> (a, MyState)

所以唯一的区别是参数顺序之一,这两个 monad 在其他方面在语义上是等价的。

在性能方面,如果不对实际代码进行基准测试,就很难确定。但是,作为一个数据点,如果您考虑以下一元动作:

foo :: StateT Double (Reader Int) Int
foo = do
  n <- ask
  modify (* fromIntegral n)
  gets floor

然后,当使用 GHC 8.6.4 使用 -O2 编译时,新类型 - 显然 - 优化掉了,如果您将签名更改为,这将生成 完全 相同的核心:

foo :: ReaderT Int (State Double) Int

除了foo 的两个参数被翻转。因此,至少在这个简单的示例中,根本没有性能差异。

从风格上讲,您可能会遇到一种情况,即一种排序导致代码比另一种更好看,但通常在它们之间没有太多选择余地。特别是,像上面这样的基本一元动作在任何一种排序下看起来都完全相同。

无缘无故,我倾向于支持 #2,主要是因为 Env -&gt; MyState -&gt; (a, MyState) 对我来说看起来更自然。

【讨论】:

  • 一个小问题:当我们谈论擦除新类型时,仅仅拥有两个同构类型是不够的;还必须检查关联的实例是否尊重同构。 (例如,考虑All 和假设的Xor,它们都展开为Bool,但其Monoid 实例不尊重idnot 同构。)这是一个非常小的狡辩但是,在这种情况下,因为实例确实是适当地对应的。
猜你喜欢
  • 2013-09-04
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 2020-07-13
相关资源
最近更新 更多