Some sources tell you the purpose of newtype is to make new types from existing types. This is only partially true. Often newtype is used in lieu of "data" to create entirely new types.
The discussion in the Haskell Wiki might be the best.
newtype Critter = Fish | Bird
newtype Dingus = Dingus {
number :: Int
id :: String
}
At this point you ought to be wondering what good this thing is and why it exists.
One reason is that newtype has less overhead (which makes some sense given all of the restrictions). Newtype can be used to create a new type based on an existing datatype, while changing the typeclass participation.
I'm going to leave the basics here, but just mention that there are also some distinctions involving laziness versus strictness. Newtype value constructors are strict, while "data" value constructors are lazy.
We run into the following on page 240 of Real World Haskell
newtype Parse a = Parse {
runParse :: ParseState -> Either String (a, ParseState)
}
This definition bears a remarkable similarity to this one:
newtype State s a = State { runState :: s -> (s, a) }
I call this the mantra of newtype magic, the famous "State" newtype.
If you can wrap your head around this, you have cracked the nut of
"newtype.
In many ways, there are no real surprises here. We have one type constructor with one field. The only unusual thing might be that the field holds a function.
Notice that both of these stand on their own. They are not wrapping or redefining some other type as is so often claimed for newtype.
Don't go running around (like I did) looking for a function elsewhere defining runParse or runState. A sneaky game with Haskell record syntax is going on here.
-- Applies a function to the internal value without
-- altering the state modification logic.
instance Functor (State s) where
fmap f (State g) = State $ \s ->
let (x, s') = g s
in (f x, s')
-- Allows for independent stateful computations to be sequenced.
instance Applicative (State s) where
pure x = State $ \s -> (x, s)
State f_g <*> State g = State $ \s ->
let (f, s') = f_g s
(x, s'') = g s'
in (f x, s'')
-- Sequentially pipes the resulting value and final state
-- of one action into the next.
instance Monad (State s) where
return = pure
(State g) >>= f = State $ \s ->
let (x, s') = g s -- Run the first stateful computation
State h = f x
in h s' -- Run the second stateful computation
There is deep magic involved with Haskell "newtype". Haskell "data" is simple and easy and the usual way to create a new type. Haskell "type" exists just to make simple synonyms, and has no surprises.
The very existence of "newtype" in the face of these is your first hint that something unexpected is going on. Newtype has special rules.
Tom's software pages / tom@mmto.org