I want something like
f :: [forall m. (Mutable v) (PrimState m) r -> m ()] -> v r -> v r -- illegal signature
f gs x = runST $ do
y <- thaw x
foldM_ (\_ g -> g y) undefined gs -- you get the idea
unsafeFreeze y
我基本上处于与Vitus评论的这个问题相同的位置:
如果你想在某个结构内保留多态函数,则需要使用特殊的数据类型(例如,新类型I = I(forall a。a -> a))或ImpredicativeTypes。
此外,请参见该问题。问题是,这些解决方案都非常丑陋。因此,我想出了第三种选择,即通过在IO中运行“应该”是ST
计算来完全避免多态性。因此,f
变为:
f :: [(Mutable v) RealWorld r -> IO ()] -> v r -> v r
f gs x = unsafePerformIO $ do
y <- thaw x
foldM_ (\_ g -> g y) undefined gs -- you get the idea
unsafeFreeze y
我选择使用 unsafe
的 IO
而不是“安全”的 ST
,虽然这让我感觉有点不太好,但如果我的替代方案是使用包装器或不确定类型...显然,我并不孤单。
在这里使用 unsafePerformIO
会有什么问题吗? 在这种情况下,它真的很不安全吗? 我需要注意哪些性能方面的问题或其他方面的问题吗?
--------------编辑----------------
下面的答案向我展示了如何完全解决这个问题,这非常好。 但出于教育目的,我仍然对原始问题(使用可变向量时的runST
与unsafePerformIO
的影响)感兴趣。
PolyModifier
比forall m. (Mutable v) (PrimState m) r -> m ()
更容易理解。除此之外,你会放弃一些类型系统给你的保证。很难说你在这里放弃了什么,因为你没有展示给我们所有的代码。但现在你正在做出像“x将永远不会再次被查看”这样的断言,因为你只是破坏了一个纯结构。 - daniel gratzerforall
移到列表外面,例如(forall m. [Mutable v (PrimState m) r -> m ()]) -> v r -> v r
,会出现什么问题?(换句话说,你确定需要在结构中存储多态的内容,而不是拥有一个多态的结构吗?) - Daniel Wagner-XImpredicativeTypes
。 - crockeea