3

I'm clear about the generic functions and generic data-types.

In the generic type:

data SB = forall x. (show x) => SB x
instance Show SB where
  show (SB x) = show x

so for any given type x, if it has a signature of Show, and there sure be a show function corresponds to it.

but when typing in ghci, e.g.

:t 1

outputs

1 :: Num a => a

if binds 1 to a name:

let a=1
:t a

now a has a true type.

The question is:

What is 1's form in the run-time system(before it has a type, it has only Num), since it can only hold some info of what it can be transformed to.

Are there some internal functions for 'packing up' the generic 'information' into real things?

For all that I know now, In haskell there should be 'generic' tags on some real things, but there should not be some 'pure generic things'.

Regards!

possible result:

reference to `1` becomes:
get_const_value_1 :: (Num a) => a
get_const_value_1 = fromIntegral (1 :: Integer)
Community
  • 1
  • 1
wuxb
  • 2,572
  • 1
  • 21
  • 30
  • BTW, your initial example is an "existential type". The type component 'x' is hidden, all we know is that it implements the `Show` interface. – Don Stewart Jun 06 '11 at 14:28
  • @Don Stewart:maybe I should make it more clearly: how does `1` become `Num` , (then `Num` become `Integer` or `Int`) – wuxb Jun 06 '11 at 14:33
  • 1
    Are you specifically wondering why binding `a = 1` results in a monomorphic (or non-generic) type? In this case, in GHCi, it is due to [defaulting and the "monomorphism restriction"](http://stackoverflow.com/questions/4179453/why-are-polymorphic-values-not-inferred-in-haskell). – Don Stewart Jun 06 '11 at 14:47

2 Answers2

4

As Don Stewart said, type classes in GHC are implemented using "dictionaries". That means that the type class Num is represented as a record of functions (I'm gonna skip the Eq and Show constraints here):

class Num a where
    fromInteger :: Integer -> a
    ...

becomes

data Num a = Num { fromInteger :: Integer -> a, ... }

When you define an instance, a new record is created with the functions from the instance:

instance Num Integer where
    fromInteger = id
    ...

becomes

numDictForInteger = Num { fromInteger = id, ... }

Now, when you use this function in a polymorphic context, the compiler doesn't know which dictionary to use, so it generates an extra parameter for it:

foo :: Num a => a
foo = 1

becomes

foo :: Num a -> a
foo numDict = fromInteger numDict 1

Notice how the constraint Num a => becomes a parameter Num a ->.


However, when you remove the polymorphism, the compiler knows which dictionary to use statically, so it goes ahead and inlines it instead of generating a parameter:

foo :: Integer
foo = 1

becomes

foo :: Integer
foo = fromInteger numDictForInteger 1

As a footnote, this is why the monomorphism restriction exists. A polymorphic value would not be a CAF since it requires the dictionary argument. This might cause significantly different performance characteristics from what you might expect and therefore you're forced to explicitly state that this behavior is what you wanted.

hammar
  • 138,522
  • 17
  • 304
  • 385
  • is that correct:1 is an Integer, warp up by function `fromIntegral`, so it equals to `foo numDict = fromInteger numDict (1 :: Integer)` – wuxb Jun 06 '11 at 15:26
2

Generic functions that are paramaterized via a type class are represented in GHC as functions that take a "dictionary". This is a data structure containing all the methods of a particular typeclass instance, when instantiated to a given type.

Thus functions may be generic (or "polymorphic") as we say in Haskell, in the typeclass methods.

For more about GHC's representation of values at runtime, see:

Don Stewart
  • 137,316
  • 36
  • 365
  • 468