Is there ever a good reason to use unsafePerformIO?

后端 未结 6 579
北海茫月
北海茫月 2020-12-24 07:04

The question says it all. More specifically, I am writing bindings to a C library, and I\'m wondering what c functions I can use unsafePerformIO with. I assume

6条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-24 07:17

    No need to involve C here. The unsafePerformIO function can be used in any situation where,

    1. You know that its use is safe, and

    2. You are unable to prove its safety using the Haskell type system.

    For instance, you can make a memoize function using unsafePerformIO:

    memoize :: Ord a => (a -> b) -> a -> b
    memoize f = unsafePerformIO $ do
        memo <- newMVar $ Map.empty
        return $ \x -> unsafePerformIO $ modifyMVar memo $ \memov ->
            return $ case Map.lookup x memov of
                Just y -> (memov, y)
                Nothing -> let y = f x
                           in (Map.insert x y memov, y)
    

    (This is off the top of my head, so I have no idea if there are flagrant errors in the code.)

    The memoize function uses and modifies a memoization dictionary, but since the function as a whole is safe, you can give it a pure type (with no use of the IO monad). However, you have to use unsafePerformIO to do that.

    Footnote: When it comes to the FFI, you are responsible for providing the types of the C functions to the Haskell system. You can achieve the effect of unsafePerformIO by simply omitting IO from the type. The FFI system is inherently unsafe, so using unsafePerformIO doesn't make much of a difference.

    Footnote 2: There are often really subtle bugs in code that uses unsafePerformIO, the example is just a sketch of a possible use. In particular, unsafePerformIO can interact poorly with the optimizer.

提交回复
热议问题