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