[Haskell-cafe] Re: do

Brandon S. Allbery KF8NH allbery at ece.cmu.edu
Mon Oct 15 19:29:04 EDT 2007

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 at kf8nh.com
system administrator [openafs,heimdal,too many hats] allbery at ece.cmu.edu
electrical and computer engineering, carnegie mellon university    KF8NH

More information about the Haskell-Cafe mailing list