May 2, 2018

Real World Haskell - state and newtype

On page 240 of the book, the following code is thrown at us:
newtype Parse a = Parse {
        runParse :: ParseState -> Either String (a, ParseState)
}
The only explanation given is that this is being introduced to encapsulate access to the Parse state. There is actually a lot more going on here, and the whole business merits several chapters on its own.

Now, if you grab your copy of "Learn you a Haskell" and turn to page 316, you will see this line:

newtype State s a = State { runState :: s -> (a,s) )
This has a remarkably similar smell to the code thrown at us in "Real World Haskell" The reader will find it useful to read pages 313 to 319 to see what this author has to say about "Stateful Computations". Truth be known, the reader will find it useful to read and carefully study chapters 12, 13, and 14 so as to work up to understanding this in a sensible way. Chapter 12 (entitled "Monoids") spends several very worthwhile pages discussing the subtilties of the Haskell newtype statement.

Newtype (and data and type)

The first thing is to be clear on what "data" and "type" do. In Haskell, "data" creates new types and "type" creates aliases for existing types. This much is fairly straightforward with no real surprises.

So what do we need "newtype" for? Many people have asked this question. The answer seems to be that while being more limiting, it is more efficient. The statement is often made that any place where "newtype" is used, "data" could be used instead, but not the reverse.

Newtype is more fussy in that it can have only a single value constructor, and that constructor can have only one field. This is the price you pay for it being faster. In effect, "type" puts a wrapper around some "data" gadget, whereas "newtype" avoids the overhead of doing that.

There is more going on of course. The value constructor introduced by "newtype" is strict, whereas the value constructor introduced by "data" is lazy. So if you assign "undefined" in a newtype value constructor, it blows up immediately. If you assign "undefined" in a data value constructor, it blows up later or maybe never. Is this vitally important, not to me at this point, but there it is.

It is worth going back to chapter 6 in "Real World Haskell" and paying close attention to what is being done with newtype there (pages 155 through 158).

Control.Monad.State

As it turns out, all of this business comes from code in the Control.Monad.State module. As Brandon Simon says, "This is crazy stuff and nothing like what we’ve seen before." Getting back to "Learn you a Haskell", he gives you some code from the Control.Monad.State module, but not the whole thing.

Even the explanation in LYAH is confusing until you realize that they are not showing you all of the code from Control.Monad.State, just pieces of it. In particular the "state" function is not shown in the book. If you really want to look at the whole thing (which is not a bad idea), you discover that this is actually a Monad Transformer, yet another new concept (but you can ignore that and just work on getting a handle on the monad that results from the transformation, namely "State"). The source in the GHC source tree is at:

ghc/libraries/transformers/Control/Monad/Trans/State/Lazy.hs

Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org