Trouble with ST's type in a transformer stack

泪湿孤枕 提交于 2019-12-12 20:40:26

问题


I am having some trouble dealing with the forall quantifier in ST's type. The following (simplified) code sample works fine, producing the expected result.

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

This is fine, if all I want to do is have ST. But in my computation, I want a state transformer computation that might also fail, so I attempt to add ExceptT to the stack.

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

Unfortunately, I get a rather bizarre error message.

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

I have only a vague understanding of the rank-2 type used by ST, so I'm not really sure how to approach this error. How can I safely put ST at the bottom of a monad transformer stack without getting problems with the forall?

(For those curious, I'm using ST because I want my computation to use a mutable array and then freeze it at the end. That shouldn't be relevant to this problem, but this is why I can't simply use State instead)


回答1:


All you need to do is replace the . behind runST by $, and then you can use ordinary return instead of return' as well.

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 ()

(At least for me this compiles, without problems.)

See this answer for the theory behind the error.



来源:https://stackoverflow.com/questions/32654814/trouble-with-sts-type-in-a-transformer-stack

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!