Haskell 2010 report section 6.4.1 says
An integer literal represents the application of the function
fromInteger
to the appropriate value of typeInteger
.
What does that "appropriate value" look like? Can I write it in source Haskell? I could of course write
x :: Integer
x = 4
But that equation is equivalent to
x = (fromInteger 4) :: Integer
Edit: hmm to avoid infinite regress that should probably be
x = (fromInteger 4?) :: Integer
in which 4?
is the mysterious value 4
at type Integer
.
so it's selecting the Integer
overloading of fromInteger
. The type of the literal (in the original x = 4
) is still 4 :: Num a => a
, it's not type Integer
.
I'm thinking about this wrt newtype
s:
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
newtype Age = MkAge Int deriving (Num, Eq, Ord, Show)
-- fromInteger is in Num
y :: Age
y = 4
z = (4 + 5 :: Age) -- no decl for z, inferred :: Age
If I ask to show y
I see MkAge 4
; if I ask to show x
I see plain 4
. So is there some invisible constructor for Integer
s?
Supplementary q for newtype
s: since I can write z = (4 + 5 :: Age)
is the constructor MkAge
really necessary?
mkAge2 :: Age -> Age
mkAge2 = id
w = mkAge2 4
mkAge3 :: Integer -> Age
mkAge3 = fromInteger
u = mkAge3 4
seems to work just as well, if I want something prefix.
Can I write it in source Haskell?
Sort of.
You can write 4 :: Integer
but 4
is already an application of fromInteger
to "an appropriate value". :: Integer
only selects an appropriate overload for fromInteger
. The application has type Integer
though, so it can function like a magic monomorphic literal.
newtype Age = MkAge Int deriving (Num, Eq, Ord, Show)
You can write 4 :: Age
now and this is OK. This has nothing to do with what Show
does. You can write your own Show
instance that prints a plain 4
instead of MkAge 4
. This is how Show
instances for all the built-in types work. The following is GHC-specific, other implementations may have different details, but the general principles are likely to be the same.
Prelude> :i Int
data Int = GHC.Types.I# Int# -- Defined in ‘GHC.Types’
Prelude> :i Integer
data Integer
= integer-gmp-1.0.2.0:GHC.Integer.Type.S# Int#
| integer-gmp-1.0.2.0:GHC.Integer.Type.Jp# {-# UNPACK #-}integer-gmp-1.0.2.0:GHC.Integer.Type.BigNat
| integer-gmp-1.0.2.0:GHC.Integer.Type.Jn# {-# UNPACK #-}integer-gmp-1.0.2.0:GHC.Integer.Type.BigNat
-- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’
As you can see, there are data constructors (and they are not that invisible!) for Int
and Integer
. We can use the one for Int
no problem.
Prelude> :set -XMagicHash
Prelude> :t 3#
3# :: GHC.Prim.Int#
Prelude> :t GHC.Types.I# 3#
GHC.Types.I# 3# :: Int
Prelude> show 3
"3"
Prelude> show $ GHC.Types.I# 3#
"3"
OK we have built an Int
with a constructor, which doesn't interfere with showing it as a plain 3
one little bit. It is an application of a bona fide constructor to an honest monomorphic literal. What about Integer
?
Prelude> GHC.Integer.Type.S# 3#
<interactive>:16:1: error:
Not in scope: data constructor ‘GHC.Integer.Type.S#’
No module named ‘GHC.Integer.Type’ is imported.
Prelude>
Hmm.
Prelude> :m + GHC.Integer.Type
<no location info>: error:
Could not load module ‘GHC.Integer.Type’
it is a hidden module in the package ‘integer-gmp-1.0.2.0’
So Integer
constructors are hidden from the programmer (intentionally I suppose). But if you were writing GHC.Integer.Type
itself you would be able to use GHC.Integer.Type.S# 3#
. This has type Integer
and is again an application of a bona fide constructor to an honest monomorphic literal.