haskell - 在变压器堆栈中展开 STT 单子(monad)?

标签 haskell polymorphism higher-rank-types

这个问题显然与讨论的问题here相关。和 here 。不幸的是,我的要求与这些问题略有不同,并且给出的答案不适用于我。我也不太明白为什么 runST 在这些情况下无法进行类型检查,这没有帮助。

我的问题是这样的,我有一段代码使用一个 monad 堆栈,或者更确切地说是单个 monad:

import Control.Monad.Except
type KErr a = Except KindError a

另一段代码需要与此集成,将其包装在 STT monad 中:

type RunM s a = STT s (Except KindError) a

在这些部分之间的接口(interface)处,我显然需要包裹和展开外层。我有以下函数可以在 KErr -> RunM 方向工作:

kerrToRun :: KErr a -> RunM s a
kerrToRun e = either throwError return $ runExcept e

但由于某种原因,我无法得到与类型检查相反的结果:

runToKErr :: RunM s a -> KErr a
runToKErr r = runST r

我正在假设,由于 RunM 的内部 monad 与 KErr 具有相同的结构,一旦我解开包装,我就可以返回它STT 层,但我似乎无法做到这一点,因为 runST 提示其类型参数:

src/KindLang/Runtime/Eval.hs:18:21:
    Couldn't match type ‘s’ with ‘s1’
      ‘s’ is a rigid type variable bound by
          the type signature for runToKErr :: RunM s a -> KErr a
          at src/KindLang/Runtime/Eval.hs:17:14
      ‘s1’ is a rigid type variable bound by
           a type expected by the context:
             STT s1 (ExceptT KindError Data.Functor.Identity.Identity) a
           at src/KindLang/Runtime/Eval.hs:18:15
    Expected type: STT
                     s1 (ExceptT KindError Data.Functor.Identity.Identity) a
      Actual type: RunM s a

我也尝试过:

runToKErr r = either throwError return $ runExcept $ runST r

为了更强有力地将 runST 与其预期返回类型隔离,以防万一这是问题的原因,但结果是相同的。

这个 s1 类型来自哪里,我如何说服 ghc 它与 s 类型相同?

最佳答案

(下面讨论的是 ST s a,但应用与 STT s m a 相同;我只是避免了下面讨论变压器版本带来的不必要的复杂性)

您看到的问题是 runST 具有类型 (forall s. ST s a) -> a 来隔离任何潜在的 (STRef -改变)来自外部、纯粹世界的计算的影响。所有 ST 计算、STRef 等所标记的 s 幻像类型的全部要点是跟踪哪个“ >ST-domain”他们所属; runST 的类型确保域之间不能传递任何内容。

您可以通过强制执行相同的不变量来编写runToKErr:

{-# language Rank2Types #-}

runToKErr :: (forall s. RunM s a) -> KErr a
runToKErr = runST

(当然,您可能会进一步意识到这个限制对于您希望编写的程序来说太强了;那时您将需要失去希望,抱歉,我的意思是您需要重新设计您的程序程序。)

至于错误消息,您无法“说服类型检查器 s1s 是同一类型”的原因是,如果我向您传递一个ST s a 对于 sa 的给定选择,这与给您一些允许您选择自己的 不同>s。 GHC 选择 s1(Skolemized 变量)作为 s,因此尝试将 ST s aST s1 a 统一>

关于haskell - 在变压器堆栈中展开 STT 单子(monad)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36830676/

相关文章:

haskell - 我将如何以无点风格重写这个回文验证器?

c++ - 使用 STL 时出现段错误

c++ - 方法返回基类而不是派生类 C++

Haskell:有没有办法从函数内部推断出函数的返回类型?

haskell - Haskell 中的换能器和单态性限制

testing - Haskell:如何使用快速检查测试(响应式(Reactive))FSM?

list - 遍历所有(行,列)可能性?

ubuntu - ubuntu : how to make work an haskell build system? 上的 Sublime Text 3

parsing - 使用替代方案的纯应用解析器

haskell - 为什么 rank-n 类型需要显式的 forall 量词?