消除列表中的幻影类型
Eliminating phantom types in a list
我在弄清楚如何 运行 列表中的 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 中 运行ning 这个,这将是一个简单的问题,将 pure . map runST
替换为 traverse runIO
(或其他),但我还没有想到了解如何绕过幻像类型参数的存在。我怀疑列表 sts
需要为不同的列表元素提供不同的类型参数,因此需要是某种说服力的异构列表,但是包装 ST monads 除了旧错误之外还会引入一个新错误。
{-# 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,它也有一个幻影类型,并被函数 runRegion :: NFData a => (forall s. R s a) -> IO a
消除。我相信 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 $ runST (mapM makeST [0..5])
简而言之,不要将 ST
操作存储在列表中;相反,使用 ST
操作来计算列表。
如果由于某种原因(什么原因?)这还不够好,那么只需对第二个示例中的 (.)
进行增量扩展即可编译:
{-# 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]
我在弄清楚如何 运行 列表中的 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 中 运行ning 这个,这将是一个简单的问题,将 pure . map runST
替换为 traverse runIO
(或其他),但我还没有想到了解如何绕过幻像类型参数的存在。我怀疑列表 sts
需要为不同的列表元素提供不同的类型参数,因此需要是某种说服力的异构列表,但是包装 ST monads 除了旧错误之外还会引入一个新错误。
{-# 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,它也有一个幻影类型,并被函数 runRegion :: NFData a => (forall s. R s a) -> IO a
消除。我相信 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 $ runST (mapM makeST [0..5])
简而言之,不要将 ST
操作存储在列表中;相反,使用 ST
操作来计算列表。
如果由于某种原因(什么原因?)这还不够好,那么只需对第二个示例中的 (.)
进行增量扩展即可编译:
{-# 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]