如何使用 unsafePerformIO 来编写 unsafeCoerce?

dfe*_*uer 7 haskell unsafe-perform-io

众所周知,这unsafePerformIO不是类型安全的。这通常通过使用它来实现来证明unsafeCoerce

box :: IORef a
box = unsafePerformIO (newIORef undefined)
{-# NOINLINE box #-}

unsafeCoerce :: a -> b
unsafeCoerce a = unsafePerformIO $
  writeIORef box a >> readIORef box
Run Code Online (Sandbox Code Playgroud)

正如我几年前所展示的,这个实现不是线程安全的。一个线程可以写入盒子,然后另一个线程可以在第一个线程可以读取之前再次写入盒子。哎呀!如何解决这个问题?

dfe*_*uer 9

正如我曾说过的那样,正确的方法是通过 an 使用强制IORef来生成unsafeCoerce函数本身,而不是生成其应用程序的单独结果。

box :: IORef x
box = unsafePerformIO (newIORef undefined)
-- This NOINLINE is essential. If this binding is inlined,
-- then unsafeCoerce = undefined.
{-# NOINLINE box #-}

unsafeCoerce :: a -> b
unsafeCoerce = unsafePerformIO $
  writeIORef box id >> readIORef box

-- Inlining this wouldn't break anything,
-- but it'd waste time with unnecessary IORef operations.
{-# NOINLINE unsafeCoerce #-}
Run Code Online (Sandbox Code Playgroud)

  • 我承认我对“正确的方式”嗤之以鼻:我们正在创造一种可憎的东西,但是嘿,我们应该小心不要以错误的方式这样做!;-) (4认同)
  • @chi,是的,这有点傻,但我觉得很有趣。 (2认同)