开发者

how does the undecided generic type represents in ghci's runtime

开发者 https://www.devze.com 2023-03-10 23:17 出处:网络
I\'m clear about the generic functions and generic data-types. In the generic type: data SB = forall x. (show x) => SB x

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 th开发者_运维百科e 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)


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.


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:

  • GHC's implementation of overloading
  • The layout of heap objects
  • The vacuum visualization tool.
0

精彩评论

暂无评论...
验证码 换一张
取 消