
The simple explanation is "because the FFI standard says so"; primitive types wrapped in newtypes automatically get wrapped and unwrapped during FFI calls. See http://www.cse.unsw.edu.au/~chak/haskell/ffi/ffi/ffise3.html#x6-120003.2 ; the FFI uses "renamed datatype" to mean newtype. Consider the following declarations translated to C:
type Weak = Word32 {- typedef HsWord32 Weak; }
Weak is just a type alias; you can use Word32 and Weak interchangeably in your code after delcaring this type.
newtype Strong = Strong Word32 {- doesn't really exist in C; google for "c strong typedef" -}
Strong behaves exactly like a Word32 at runtime, in terms of storage, but the typechecker can distinguish it from Word32.
data Holder = Holder Word32 {- typedef struct { HsWord32 x; } Holder; -}
Holder, on the other hand, is entirely separate from Word32; in fact, there are strictly more values in Haskell of type Holder than there are of type Word32:
ha, hb, hc :: Holder -- can all be distinguished at runtime ha = undefined hb = Holder undefined hc = Holder 0
sa, sb :: Strong -- cannot be distinguished sa = undefined sb = Strong undefined