如何使用unsafePerformIO来编写unsafeCoerce?
众所周知,这unsafePerformIO不是类型安全的。这通常通过使用它来实现来证明unsafeCoerce:
box :: IORef a
box = unsafePerformIO (newIORef undefined)
{-# NOINLINE box #-}
unsafeCoerce :: a -> b
unsafeCoerce a = unsafePerformIO $
writeIORef box a >> readIORef box
正如我几年前所展示的,这个实现不是线程安全的。一个线程可以写入盒子,然后另一个线程可以在第一个线程可以读取之前再次写入盒子。哎呀!如何解决这个问题?
回答
正如我曾说过的那样,正确的方法是通过 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 #-}
- 我承认我对“正确的方式”嗤之以鼻:我们正在创造一种可憎的东西,但是嘿,我们应该小心不要以错误的方式这样做!;-)
- @chi,是的,这有点傻,但我觉得很有趣。