在变压器堆栈中ST型的故障

时间:2015-09-18 14:44:45

标签: haskell types monad-transformers

我在处理forall类型中的ST量词时遇到了一些问题。以下(简化)代码示例工作正常,产生预期结果。

import Control.Monad
import Control.Monad.ST

return' :: a -> ST s a
return' = return

function :: a -> a
function x = runST $ do
               -- Some complicated expression eventually producing a result
               return' x

这很好,如果我想做的就是ST。但是在我的计算中,我想要一个也可能失败的状态变换器计算,所以我尝试将ExceptT添加到堆栈中。

import Control.Monad
import Control.Monad.ST
import Control.Monad.Except

return' :: a -> ExceptT String (ST s) a
return' = return

function :: a -> Either String a
function x = runST . runExceptT $ do
               -- Some complicated expression that might fail
               return' x

不幸的是,我收到了一条相当奇怪的错误信息。

example.hs:9:14:
    Couldn't match type `ST s0 (Either String a)'
                   with `forall s. ST s (Either String a)'
    Expected type: ST s0 (Either String a) -> Either String a
      Actual type: (forall s. ST s (Either String a))
                   -> Either String a
    Relevant bindings include
      x :: a (bound at example.hs:9:10)
      function :: a -> Either String a (bound at example.hs:9:1)
    In the first argument of `(.)', namely `runST'
    In the expression: runST . runExceptT

我对ST使用的rank-2类型只有模糊的理解,因此我不确定如何处理此错误。如何安全地将ST放在monad变换器堆栈的底部而不会出现forall的问题?

(对于那些好奇的人,我使用ST,因为我希望我的计算使用一个可变数组,然后在最后冻结它。这不应该与这个问题相关,但是这就是为什么我不能简单地使用State

1 个答案:

答案 0 :(得分:4)

您需要做的就是将.替换为runST $,然后您也可以使用普通return而不是return'

import Control.Monad
import Control.Monad.ST
import Control.Monad.Except

function :: a -> Either String a
function x = runST $ runExceptT $ do
               return x

main = return ()

(至少对我而言,编译没有问题。)

请参阅this answer了解错误背后的理论。