我最喜欢Haskell的一点就是编译器能够通过函数签名在IO单子中定位副作用。然而,通过导入2个GHC基元,似乎很容易绕过这种类型检查:
{-# LANGUAGE MagicHash #-}
import GHC.Magic(runRW#)
import GHC.Types(IO(..))
hiddenPrint :: ()
hiddenPrint = case putStrLn "Hello !" of
IO sideEffect -> case runRW# sideEffect of
_ -> ()
hiddenPrint
的类型是 unit,但当调用该函数时会触发副作用(它会输出 Hello)。除了不信任任何人导入 GHC 原语外,是否有办法禁止这些隐藏的 IOs?
System.IO.Unsafe
并使用unsafePerformIO
似乎更容易 ;). 虽然很容易绕过,但是 不安全的. - ZetaunsafeDupablePerformIO (IO m) = case runRW# m of (# _, a #) -> a
这段代码完全相同,我之前不知道这个模块 :) 当我阅读简化器的核心时,偶然发现了runRW#
。 - V. SemeriarealWorld#
而非runRW#
更不安全。 - dfeuer