我想要像这样的
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实际上,我在this question的位置和维图斯说的一样:
如果希望将多态函数保留在某些结构中,则需要专门的数据类型(例如,newtype i=i(foralla.a -> a))或ImpredicativeTypes。
另外,请参见this question。问题是,这两者都是非常丑陋的解决方案。因此,我提出了第三种选择,即通过在ST中运行“应该”的IO计算来完全避免多态性。因此,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路由有点脏,但是如果我的选择是包装器或非谓词类型.显然,I'm not alone.
有什么理由不让我在这里使用unsafePerformIO吗?在这种情况下,它真的不安全吗?是否有性能方面的考虑或其他我应该知道的事情?
--------------EDIT----------------
下面的答案告诉我如何彻底解决这个问题,这是很棒的。但我仍然对最初的问题感兴趣(当使用可变向量时,runST对unsafePerformIO的含义)。
发布于 2013-11-15 03:41:43
我还不能说我完全理解问题陈述,但是下面的文件在GHC 7.6.2下编译时没有错误。它的主体与第一个示例相同(特别是根本不调用unsafePerformIO );主要区别是forall被移出所有类型的构造函数之外。
{-# LANGUAGE RankNTypes #-}
import Control.Monad
import Control.Monad.Primitive (PrimState)
import Control.Monad.ST
import Data.Vector.Generic hiding (foldM_)
f :: Vector v r => (forall m. [Mutable v (PrimState m) r -> m ()]) -> v r -> v r
f gs x = runST $ do
y <- thaw x
foldM_ (\_ g -> g y) undefined gs
unsafeFreeze y现在让我们来讨论ST与IO之间的问题。它之所以被称为unsafePerformIO而不是unusablePerformIO,是因为它附带了一个无法被编译器检查的证明负担:运行unsafePerformIO的东西必须表现得好像它是引用透明的。由于ST操作提供了一个(编译器检查)的证据,证明在使用runST执行时它们的行为是透明的,这意味着在ST中使用unsafePerformIO不会比在使用runST时使用unsafePerformIO更危险。
但是:从软件工程的角度来看是有危险的。由于这个证明不再是编译器检查的,因此将来的重构更容易违反使用unsafePerformIO的安全条件。因此,如果有可能避免它(就像在这里一样),您应该努力做到这一点。(此外,“没有更多的危险”并不意味着“没有危险”:您正在发出的unsafeFreeze调用有它自己的证明责任,您必须满足这一点;但是,为了使ST代码正确,您已经必须满足该证明责任。)
https://stackoverflow.com/questions/19982295
复制相似问题