Skip to content

Ghci appears to lose sharing (of IORef created using unsafePerformIO) in interactive mode, but not in definitions in a file. when ghc does not.

Summary

This is an issue in which ghci appears to lose sharing of definitions, in a way which breaks code using unsafePerformIO, but only sometimes--depending on how the code is invoked. Maybe the answer is "What did you expect, the answer's in the name", but this was sufficiently unexpected to report it anyway.

Steps to reproduce

Here's the code:

module Main(main,demands) where

import Data.IORef
import System.IO.Unsafe

demands xs = (observe xs,
              reverse (unsafePerformIO (putStrLn "read" >> readIORef ref)))
  where
    ref = unsafePerformIO (newIORef (take 0 xs))
    observe [] = []
    observe (x:xs) = unsafePerformIO $ do
      putStrLn $ "write " ++ show x
      modifyIORef ref (x:)
      return (x:observe xs)

main = do
  let p = demands [1..3]
  print (length (fst p))
  print (snd p)

and here's the ghci session:

C:\Users\johnh\Desktop>ghci Main.hs
GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
Loaded package environment from C:\Users\johnh\AppData\Roaming\ghc\x86_64-mingw32-8.10.7\environments\default
[1 of 1] Compiling Main             ( Main.hs, interpreted )
Ok, one module loaded.
*Main> main
write 1
write 2
write 3
3
read
[1,2,3]
*Main> -- let's do that again slowly
*Main> let p = demands [1..3]
*Main> length (fst p)
write 1
write 2
write 3
3
*Main> snd p
read
[]

WHAT??? Why is that last line different?

This run was under windows using ghc 8.10.7, but we've observed the same behaviour under Linux, on the Mac, and with several versions of ghc including 9.8.2.

Note that Main.hs is interpreted in this case, and that is important. If Main is compiled, and loaded into ghci, then the strange behaviour disappears (i.e. the last line is also [1,2,3]).

So there's something about the interpretation of the interpreted demands function, that is different when it is called from the interpreted definition of main, and from the interactive top level.

Expected behavior

I expected the same result at the interactive ghci prompt as running the same code from a function definition, namely [1,2,3].

Environment

  • GHC version used: 8.10.7 et al
  • Operating System: Windows 11, Ubuntu 24.04, Mac
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information