
On Oct 15, 2007, at 19:00 , ChrisK wrote:
Brandon S. Allbery KF8NH wrote:
Use the source of unsafePerformIO as an example of how to write code which passes around RealWorld explicitly, but without unencapsulating it like unsafePerformIO does.
The main problem here, I think, is that because all the GHC runtime's functions that interact with RealWorld (aside from unsafe*IO) are themselves only exported wrapped up in IO, you can't (as far as I know) get at the lower level internal (e.g.) putStrLn' :: RealWorld -> String -> (# RealWorld,() #) to do I/O in a direct/explicit/non-monadic style. In theory, one could export those and use them directly.
Well, if you import GHC.IOBase then you get
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
unIO :: IO a -> (State# RealWorld -> (# State# RealWorld, a #)) unIO (IO a) = a
Then the type of putStrLn:
-- putStrLn :: String -> IO ()
means that putStrLn' can be defined as
putStrLn' :: String -> State# RealWorld -> (# State# RealWorld, a #) putStrLn' = unIO . putStrLn
Now you have the unboxed tuple and need to work with many 'case' statements to accomplish anything.
Also you need to get you hand on State# RealWorld either (1) Honestly, by wrapping your code in IO again and using it normally (2) From a copy, via unsafeInterleaveIO (3) From nowhere, via unsafePerformIO
(4) Honestly but unwrapped, by defining "main" in the same desugared way (takes State# RealWorld and returns (# State# RealWorld,a #) (or (# State# RealWorld,() #) if you stick to the H98 definition of main's type), allowing the runtime to pass it in and otherwise not doing anything other than propagating it. My real problem was that I incorrectly recalled IO's type to be based on ST, not State (i.e. had a forall to prevent anything from being able to do anything to/with the State# RealWorld other than pass it on unchanged without triggering a type error). I should have realized that was wrong because unsafePerformIO is itself expressible in Haskell (-fglasgow-exts is needed to make # an identifier character and to enable unboxed types and unboxed tuples, but does not make it possible to cross an existential type barrier). -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH