【问题标题】:Arbitrary monad transformer stack in type variable类型变量中的任意单子变压器堆栈
【发布时间】:2016-07-26 16:31:00
【问题描述】:

考虑以下sn-p

import Control.Monad.Trans
import Control.Monad.Trans.Except
import Control.Monad.Trans.State

newtype MyTransT m a = MyTransT (m a)

foo :: (MonadTrans t, Monad (t (Either e))) => MyTransT (t (Either e)) a -> a
foo = undefined

bar :: MyTransT (StateT Int (Either e)) a
bar = undefined

baz :: MyTransT (StateT Int (StateT Int (Either e))) a
baz = undefined

x = foo bar -- works

y = foo baz -- doesn't work

本质上,我正在尝试创建一个接受 monad 转换器堆栈的函数,指定堆栈的顶部和底部,而中间可以是任何东西。

在摸索了一会儿为什么foo bazCouldn't match type ‘StateT Int (Either e1)’ with ‘Either e0’ 拒绝后,我终于想到,在这种情况下,我假设tStateT Int (StateT Int),这不仅不是MonadTrans,它的类型/种类不正确。

有什么方法可以完成我想做的事情,或者是时候尝试不同的方法了吗?

【问题讨论】:

  • 您能举一些具体的例子来说明您希望foo 在实践中如何工作吗?
  • 假设你有一个T 类型,它可以被认为是一个V 类型的容器和K 类型的键。现在想象每个V 也遵循这种模式。我想要foo :: StateT V (t (Either e)) a -> StateT T (ReaderT K (t (Either e))) a。这将对V 进行有状态操作,并将它们提升为T 上的有状态操作,这些操作具有K 的环境。基本上是一个树形结构,我可以在不更改现有代码的情况下无限向上和向下扩展。
  • 具体的例子在这里会更有帮助。并随时将其放在您的问题中,这样更容易阅读。
  • 不幸的是,这是我所能得到的最具体的,这不是针对特定的应用程序或项目,这更像是实验性的思考。我会看看我是否能找到一些真正有用的情况。
  • 一个monad转换器栈是一个。您无法指定堆栈底部的内容。

标签: haskell monads monad-transformers parametric-polymorphism


【解决方案1】:

foo baz 不进行类型检查的原因是t 不是Either e monad 之上的转换器—​​—它是StateT Int (Either e) monad 之上的转换器。

这是它的解析方式:

 baz :: MyTransT (StateT Int (StateT Int (Either e))) a
                  \________/ \_____________________/
                       t            m                 a

请注意,m不是Either e 的形式。

您可以创建一个新的转换器,例如StateTIntStateTInt,然后写 像这样的巴兹:

 baz :: MyTransT (StateTIntStateInt (Either e)) a

然后它会键入检查。例如:

type StateTIntStateTInt = StateT (Int,Int)

baz' :: MyTransT (StateTIntStateTInt (Either e)) a
baz' = undefined

test = foo baz'

但是,即使您解决了类型问题,我也怀疑您会去 能够编写函数foo。考虑应该返回什么 对于bar这个特定值:

bar0 :: MyTransT (StateT Int (Either String)) Int
bar0 = MyTransT $ lift $ Left "blather"

foo bar0 应该返回什么 Int 值?

【讨论】:

  • 我意识到了这一点,甚至在问题中指出了这一点。关键是foo 应该能够接受任意的转换器堆栈,因此为每种可能性创建一个新类型似乎不太可能。另外,foo 的返回类型是占位符,sn-p 只是为了演示问题。实际上,foo 会返回一个与 t (Either e) 相关的值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-03
  • 2018-09-10
  • 1970-01-01
相关资源
最近更新 更多