2

我在弄清楚如何在列表中的 ST monad 中运行计算时遇到了一些麻烦。

import Data.STRef
import Control.Monad.ST

makeST :: Int -> ST s Int
makeST x = do
    r <- newSTRef x
    readSTRef r

main :: IO [Int]
main = pure $ map runST sts
  where sts = map makeST [0..5]

但是尝试编译它会出现以下错误:

    • Couldn't match type ‘ST s0 Int’ with ‘forall s. ST s Int’
      Expected type: ST s0 Int -> Int
        Actual type: (forall s. ST s Int) -> Int
    • In the first argument of ‘map’, namely ‘runST’
      In the second argument of ‘($)’, namely ‘map runST sts’
      In the expression: pure $ map runST sts

如果我在 IO monad 中运行它,这将是一个简单的替换pure . map runSTtraverse runIO(或其他)的问题,但我还没有弄清楚如何绕过幻像类型参数的存在。我怀疑该列表sts需要为不同的列表元素具有不同的类型参数,因此需要是具有某种说服力的异构列表,但是包装 ST 单子只会引入旧错误之外的新错误。

{-# LANGUAGE RankNTypes #-}

newtype WrappedST = WrappedST { unwrap :: forall s. ST s Int }

main :: IO [Int]
main = pure $ map (runST . unwrap) sts
  where sts = map (WrappedST . makeST) [0..5]
    • Couldn't match type ‘ST s1 Int’ with ‘forall s. ST s Int’
      Expected type: ST s1 Int -> WrappedST
        Actual type: (forall s. ST s Int) -> WrappedST
    • In the first argument of ‘(.)’, namely ‘WrappedST’
      In the first argument of ‘map’, namely ‘(WrappedST . makeST)’
      In the expression: map (WrappedST . makeST) [0 .. 5]

处理此问题的最佳方法是什么,其中幻像类型变量被函数消除runST,因此应该是统一的,但我无法说服类型检查器?

注意:我试图弄清楚的实际示例涉及inline-r包中的 R monad,它也有一个幻像类型,并用 function 消除runRegion :: NFData a => (forall s. R s a) -> IO a。我相信 ST monad 中的这个例子也应该抓住这里的根本问题,并且更广为人知。

4

1 回答 1

3

也许这已经足够了:

import Data.STRef
import Control.Monad.ST

makeST :: Int -> ST s Int
makeST x = do
    r <- newSTRef x
    readSTRef r

main :: IO [Int]
main = pure $ runST (mapM makeST [0..5])

简而言之,不要将ST动作存储在列表中;相反,使用一个ST动作来计算一个列表。

如果由于某种原因(什么原因?)这还不够好,那么只需(.)在第二个示例中对 s 进行增量扩展即可编译:

{-# LANGUAGE RankNTypes #-}
import Data.STRef
import Control.Monad.ST

makeST :: Int -> ST s Int
makeST x = do
    r <- newSTRef x
    readSTRef r

newtype WrappedST = WrappedST { unwrap :: forall s. ST s Int }

main :: IO [Int]
main = pure $ map (\x -> runST (unwrap x)) sts
  where sts = map (\x -> WrappedST (makeST x)) [0..5]
于 2021-01-20T01:25:24.577 回答