MichaelI've filed this as a bug with GHC[2].One last question on the GHC front, however. It *does* seem like there's still a bug in GHC here, since presumably case-ing on an unboxed tuple should force evaluation of both of its values. Indeed, after going through the above debugging, I can reproduce the issue using just primops:seems to solve the problem. I think this is the right approach for now, and I've sent a pull request to primitive with this tweak[1].primitive_ f = primitive (\s# ->this is starting to make sense. unsafeInlineIO is completely ignoring the resulting state value, as can be seen by its implementation:So it appears the bug is in writeArray, or more likely in primitive_. Sure enough, setting NOINLINE on primitive_ *does* resolve the issue. And looking at the definition of primitive_:it works as expected. Similarly, the following tweak fixes the example as well:let unit = unsafeWriteArray arr 0 'B'and then replace my unit above with:This behavior only occurs with optimizations turned on (unsurprising, given Felipe's find about the simplifier pass). Now, if I define a new operation:tl;dr: Thanks to Felipe's comments, I think I've found the issue, which is in the primitive package, together with a possible GHC bug. Following is my blow-by-blow walk through on this issue.
However, it's not reproducible with the underlying primops:
OK, a little more information, and a simpler repro. This is reproducible entirely with the primitive package:
import Control.Monad.Primitive
import Data.Primitive.Arrayarr <- newArray 1 'A'
main :: IO ()
main = do
let unit = unsafeInlineIO $ writeArray arr 0 'B'
readArray arr 0 >>= print
return $! unit
readArray arr 0 >>= print
{-# LANGUAGE MagicHash, UnboxedTuples #-}
import GHC.IO (IO (..))
import GHC.Prim
writeB :: MutableArray# RealWorld Char -> ()
writeB arr# =
case writeArray# arr# 0# 'B' realWorld# of
_ -> ()
read0 :: MutableArray# RealWorld Char -> IO Char
read0 arr# = IO $ \s0# -> readArray# arr# 0# s0#
test :: IO ((), IO Char)
test = IO $ \s0# ->
case newArray# 1# 'A' s0# of
(# s1#, arr# #) ->
(# s1#, (writeB arr#, read0 arr#) #)(unit, getter) <- test
main :: IO ()
main = do
getter >>= print
return $! unit
getter >>= print
unsafeWriteArray :: MutableArray RealWorld a -> Int -> a -> ()
unsafeWriteArray (MutableArray arr#) (I# i#) x =
case writeArray# arr# i# x realWorld# of
_ -> ()
arr@(MutableArray arr#) <- newArray 1 'A'
let unit =
case writeArray# arr# 0# 'B' realWorld# of
_ -> ()
primitive_ f = primitive (\s# -> (# f s#, () #))
unsafeInlineIO m = case internal m realWorld# of (# _, r #) -> r
Therefore `f s#` is never getting evaluated. However, if we force evaluation by switching to:
case f s# of
s'# -> (# s'#, () #))
{-# LANGUAGE MagicHash, UnboxedTuples #-}
import GHC.IO (IO (..))
import GHC.Prim
writeB :: MutableArray# RealWorld Char -> IO ()
writeB arr# =
IO $ \s0# ->
(# writeArray# arr# 0# 'B' s0#, () #)
inlineWriteB :: MutableArray# RealWorld Char -> ()
inlineWriteB arr# =
case f realWorld# of
(# _, x #) -> x
where
IO f = writeB arr#
test :: IO Char
test = IO $ \s0# ->
case newArray# 1# 'A' s0# of
(# s1#, arr# #) ->
case seq# (inlineWriteB arr#) s1# of
(# s2#, () #) ->
readArray# arr# 0# s2#
main :: IO ()
main = test >>= print
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe