haskellunsafe-perform-io

Sampling an MVar, can I avoid unsafePerformIO?


I have

sample :: MVar a -> IO [a]
sample v = do
   a <- takeMVar v
   pure (a:unsafePerformIO (sample v))

which appears to be a legitimate use of unsafePerformIO to me. But I am very interested to know how to avoid it! Is there a pattern for this use already?


Solution

  • You can implement a similar function using a thread, a Chan and getChanContents:

    sample :: MVar a -> IO [a]
    sample v = do
       c <- newChan
       forkIO $ forever $ takeMVar v >>= writeChan c
       getChanContents c   
    

    The thread/getChanContents approach is slightly better, since at least you can rely on the MVar being continuously taken. Instead, the unsafePerformIO approach will run takeMVar at impredictable points, making the putMVars blocking in a similarly impredictable way. Of course, the getChanContents approach will buffer all the data, possibly requiring more memory.

    However, both approaches are essentially similar to lazy IO, which is best to be avoided, in my opinion.