Generics 未确定的泛型类型在ghci';s运行时

Generics 未确定的泛型类型在ghci';s运行时,generics,haskell,types,functional-programming,runtime,Generics,Haskell,Types,Functional Programming,Runtime,我很清楚通用函数和通用数据类型。 在泛型类型中: data SB = forall x. (show x) => SB x instance Show SB where show (SB x) = show x 因此,对于任何给定类型x,如果它的签名为Show,那么肯定有一个Show函数与之对应 但在ghci中键入时,例如 :t 1 输出 1 :: Num a => a 如果将1绑定到名称: let a=1 :t a 现在a有了一个真正的类型 问题是: 在运行时系统中,1

我很清楚通用函数和通用数据类型。

在泛型类型中:

data SB = forall x. (show x) => SB x
instance Show SB where
  show (SB x) = show x
因此,对于任何给定类型
x
,如果它的签名为
Show
,那么肯定有一个
Show
函数与之对应

但在ghci中键入时,例如

:t 1
输出

1 :: Num a => a
如果将
1
绑定到名称:

let a=1
:t a
现在
a
有了一个真正的类型

问题是: 在运行时系统中,
1
的形式是什么(在它有类型之前,它只有
Num
),因为它只能保存它可以转换成什么的一些信息

是否有一些内部功能可以将一般的“信息”打包成真实的东西

据我所知,在haskell中,应该有一些真实事物的“通用”标记,但不应该有一些“纯通用事物”

问候

可能的结果:


通过类型类参数化的泛型函数在GHC中表示为采用“字典”的函数。这是一个数据结构,当实例化为给定类型时,它包含特定typeclass实例的所有方法

因此,函数可能是泛型的(或“多态的”),正如我们在Haskell中所说的,在typeclass方法中

有关GHC在运行时表示值的更多信息,请参阅:

  • GHC的
  • 这个

正如Don Stewart所说,GHC中的类型类是使用“字典”实现的。这意味着类型类
Num
表示为函数的记录(我将跳过
Eq
Show
约束):

变成

data Num a = Num { fromInteger :: Integer -> a, ... }
numDictForInteger = Num { fromInteger = id, ... }
foo :: Num a -> a
foo numDict = fromInteger numDict 1
foo :: Integer
foo = fromInteger numDictForInteger 1

定义实例时,将使用实例中的函数创建新记录:

instance Num Integer where
    fromInteger = id
    ...
变成

data Num a = Num { fromInteger :: Integer -> a, ... }
numDictForInteger = Num { fromInteger = id, ... }
foo :: Num a -> a
foo numDict = fromInteger numDict 1
foo :: Integer
foo = fromInteger numDictForInteger 1

现在,当您在多态上下文中使用此函数时,编译器不知道要使用哪个字典,因此它会为它生成一个额外的参数:

foo :: Num a => a
foo = 1
变成

data Num a = Num { fromInteger :: Integer -> a, ... }
numDictForInteger = Num { fromInteger = id, ... }
foo :: Num a -> a
foo numDict = fromInteger numDict 1
foo :: Integer
foo = fromInteger numDictForInteger 1
请注意约束
Num a=>
如何成为参数
Num a->


但是,当您删除多态性时,编译器知道静态使用哪个字典,因此它将继续并将其内联,而不是生成参数:

foo :: Integer
foo = 1
变成

data Num a = Num { fromInteger :: Integer -> a, ... }
numDictForInteger = Num { fromInteger = id, ... }
foo :: Num a -> a
foo numDict = fromInteger numDict 1
foo :: Integer
foo = fromInteger numDictForInteger 1


作为脚注,这就是为什么存在单态限制。多态值不会是CAF,因为它需要dictionary参数。这可能会导致性能特征与您预期的显著不同,因此您必须明确声明此行为是您想要的。

顺便说一句,您最初的示例是“存在类型”。类型组件“x”是隐藏的,我们只知道它实现了
Show
接口。@唐·斯图尔特:也许我应该把它说得更清楚一点:
1
如何变成
Num
,(然后
Num
变成
Integer
Int
)您是否特别想知道为什么绑定
a=1
会导致单态(或非泛型)类型?在这种情况下,在GHCi中,这是由于。这是否正确:1是一个整数,由函数
from integral
向上扭曲,因此它等于
foo numDict=from Integer numDict(1::Integer)