Question

On page 321 of Real World Haskell

There are these codes,

...

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype AInt = A { unA::Int }
    deriving (Show, Eq, Num)

instance Monoid AInt where
    mempty = 0

My confusion is why it is

mempty = 0

but not

mempty = A 0

?


I also noticed that both

ghci> 0 :: AInt

and

ghci> A 0 :: AInt

give me the same response

A { unA = 0 }

Would someone please tell me what is the difference between theses two?

Was it helpful?

Solution

The trick here is with the GeneralizedNewtypeDeriving extension. In particular, this lets us derive any class for a newtype as long as the underlying type is an instance. All this does is copy over the instance from the old type to the new type.

In this particular case, AInt derives Num. This means that AInt is an instance of Num using the same code as Int (with everything wrapped in A constructors as appropriate). This includes Int's fromInteger function.

The fromInteger function is defined in terms of Int's fromInteger, looking something like this:

fromInteger i = A (fromInteger i)

Since 0 is polymorphic--it has the type 0 :: Num a => a--it's a valid constant for any type in Num. Thanks to the newtype deriving, this includes AInt, using the fromInteger function above. This means there is really no difference between 0 :: AInt an A 0 :: AInt.

OTHER TIPS

Numeric literals like 0 are overloaded and have the type 0 :: Num a => a, which means that they can be any type for which there is a Num instance, depending on the context. This happens via the fromInteger function in the Num type class, so when you type 0 it is treated as if you'd written fromInteger 0.

By using GeneralizedNewtypeDeriving, GHC has (effectively1) written a Num instance for your class looking something like this:

instance Num AInt where
  fromInteger n = A (fromInteger n)
  ...

So when you write 0 :: AInt, this expands to fromInteger 0 :: AInt which is (by the definition above) equal to A (fromInteger 0) which is the same as if you had written A 0.

1 GeneralizedNewtypeDeriving doesn't actually write a new intance. It just performs the necessary casts to use the existing one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top