haskell - runST 与 unsafePerformIO 的实际意义

标签 haskell monads impredicativetypes

我想要类似的东西

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 相同的位置Vitus 评论道:

[I]f you want keep polymorphic functions inside some structure, you need either specialized data type (e.g. newtype I = I (forall a. a -> a)) or 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路线比较“安全”ST路线,但如果我的替代方案是包装或暗示类型...显然,I'm not alone.

有什么理由我不应该使用 unsafePerformIO这里?在这种情况下,真的一点都不安全吗?是否有性能考虑或其他我应该注意的事项?

--------------编辑----

下面的答案向我展示了如何完全解决这个问题,这很棒。但我仍然对出于教育目的的原始问题(runSTunsafePerformIO 的含义)感兴趣。

最佳答案

我不能说我完全理解问题陈述,但以下文件在 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 on 必须表现得好像它是引用透明的。由于ST Action 带有(经过编译器检查的)证明,证明它们在使用 runST 执行时行为透明。 ,这意味着使用 unsafePerformIO 没有更多危险关于将在 ST 中进行类型检查的代码比使用 runST .

但是 : 从软件工程的角度来看存在危险。由于证明不再经过编译器检查,因此将来的重构更容易违反可以安全使用 unsafePerformIO 的条件。 .因此,如果可以避免它(因为它似乎在这里),你应该努力这样做。 (此外,“不再有危险”并不意味着“没有危险”:您正在调用的 unsafeFreeze 有其自己必须满足的举证责任;但是您已经必须满足该举证责任ST 代码是正确的。)

关于haskell - runST 与 unsafePerformIO 的实际意义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19982295/

相关文章:

haskell - 以下 foldl 实现有什么问题?

haskell - mapM 如何与 Haskell 中的 const 函数一起工作?

haskell - 为什么 id 的类型不能专门化为 (forall a.a -> a) -> (forall b.b -> b)?

haskell - 使用 RankNTypes 编码的 System-F 自然数的 "case"运算符无法进行类型检查

haskell - 如何缩短这样的 Haskell 实现?

haskell - "lemma"函数的一般类型应该如何理解?

haskell - 获取树中定义的整数的总和和乘积

functional-programming - 为什么 Maybe/Option 在 Clojure 中的使用不那么普遍?

haskell - 我们可以用 Alternative 做什么,但不能用 Monoid 做什么?

scala - 命令式类型与普通的旧子类型