我想要类似的东西
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
我基本上处于与以前相同的位置这个问题维特斯评论道:
[I]如果你想在某个结构中保留多态函数,你需要专门的数据类型(例如 newtype I = I (forall a.a -> a))或 ImpredicativeTypes。
另请参阅这个问题。问题是,这些都是非常丑陋的解决方案。所以我提出了第三种选择,即通过运行“应该”的内容来完全避免多态性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
路线与“安全”路线相比ST
路线,但如果我的选择是包装器或命令类型......显然,我不孤独。
有什么理由我不应该 use unsafePerformIO
这里?这样的话,真的一点都不安全吗?是否有性能方面的考虑因素或其他我应该注意的事情?
- - - - - - - 编辑 - - - - - - - -
下面的答案向我展示了如何完全解决这个问题,这很棒。但我仍然对原来的问题感兴趣(暗示runST
vs unsafePerformIO
当使用可变向量时)用于教育目的。
我还不能说我完全理解问题陈述,但以下文件在 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
vs IO
问题。它被称为的原因unsafePerformIO
并不是unusablePerformIO
是因为它带有编译器无法检查的证明负担:您正在运行的东西unsafePerformIO
on 的行为必须表现为引用透明。自从ST
操作带有(编译器检查的)证明,表明它们在执行时行为透明runST
,这意味着使用时不再有危险unsafePerformIO
在将进行类型检查的代码上ST
比使用中的runST
.
BUT:从软件工程的角度来看存在危险。由于证明不再经过编译器检查,因此将来的重构更容易违反安全使用的条件unsafePerformIO
。因此,如果可以避免它(就像这里看起来的那样),您应该努力这样做。 (此外,“不再有危险”并不意味着“没有危险”:unsafeFreeze
您拨打的电话有其自身的举证责任,您必须满足;但那时你已经必须满足证明责任ST
代码正确。)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)