Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can anybody explain GHC's definition of IO?

Tags:

io

haskell

ghc

The title is pretty self-descriptive, but there's one part that caught my attention:

newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))

Stripping the newtype, we get:

State# RealWorld -> (# State# RealWorld, a #)

I don't know what State# stands for. Can we replace it with State like this:

State RealWorld -> (State RealWorld, a)

And can that be expressed as this, then?

State (State RealWorld) a

This particular construct caught my attention.


I know that conceptually,

type IO a  =  RealWorld -> (a, RealWorld)

And @R.MartinhoFernandes told me that I can actually think about that implementation as ST RealWorld a, but I'm just curious why the particular GHC version is written like it is.

like image 652
Bartek Banachewicz Avatar asked Feb 18 '15 15:02

Bartek Banachewicz


People also ask

Does Haskell have side effects?

Haskell is a pure language Moreover, Haskell functions can't have side effects, which means that they can't effect any changes to the "real world", like changing files, writing to the screen, printing, sending data over the network, and so on.

How IO monad works?

IO Monad is simply a Monad which: Allows you to safely manipulate effects. Transform the effects into data and further manipulate it before it actually gets evaluated.

What is IO Haskell?

IO is the way how Haskell differentiates between code that is referentially transparent and code that is not. IO a is the type of an IO action that returns an a . You can think of an IO action as a piece of code with some effect on the real world that waits to get executed.

How is Haskell IO implemented?

It's implemented using unsafeInterleaveIO , which does trickery behind the scenes to allow lazy I/O. It's not a good example of how IO is supposed to work.


1 Answers

It's probably best not to think too deeply about GHC's implementation of IO, because that implementation is weird and shady and works most of the time by compiler magic and luck. The broken model that GHC uses is that an IO action is a function from the state of the entire real world to a value paired with a new state of the entire real world. For humorous proof that this is a strange model, see the acme-realworld package.

The way this "works": Unless you import weird modules whose names start with GHC., you can't ever touch any of these State# things. You're only given access to functions that deal in IO or ST and that ensure the State# can't be duplicated or ignored. This State# is threaded through the program, which ensures that the I/O primitives actually get called in the proper order. Since this is all for pretend, the State# is not a normal value at all—it has a width of 0, taking 0 bits.

Why does State# take a type argument? That's a much prettier bit of magic. ST uses that to force polymorphism needed to keep state threads separate. For IO, it's used with the special magic RealWorld type argument.

like image 179
dfeuer Avatar answered Oct 05 '22 03:10

dfeuer