对于带有约束的表达式,Haskell中的求值是如何工作的
假设我用GHCi写:对于带有约束的表达式,Haskell中的求值是如何工作的,haskell,polymorphism,evaluation,strictness,Haskell,Polymorphism,Evaluation,Strictness,假设我用GHCi写: GHCi> let x = 1 + 2 :: Integer GHCi> seq x () GHCi> :sprint x GHCi按预期打印x=3 但是, GHCi> let x = 1 + 2 GHCi> seq x () GHCi> :sprint x 收益率x=\uu 这两个表达式之间唯一的区别是它们的类型(Integervsnuma=>a)。我的问题是到底发生了什么,以及为什么在后一个例子中似乎没有计算x。主要问题是 let
GHCi> let x = 1 + 2 :: Integer
GHCi> seq x ()
GHCi> :sprint x
GHCi按预期打印x=3
但是,
GHCi> let x = 1 + 2
GHCi> seq x ()
GHCi> :sprint x
收益率x=\uu
这两个表达式之间唯一的区别是它们的类型(Integer
vsnuma=>a
)。我的问题是到底发生了什么,以及为什么在后一个例子中似乎没有计算x
。主要问题是
let x = 1 + 2
为所有a定义类型为的多态值。Num a=>a
,其计算结果与函数类似
每次使用x
都可以使用不同的类型,例如x::Int
,x::Integer
,x::Double
等等。这些结果不会以任何方式“缓存”,而是每次重新计算,就好像x
是一个被多次调用的函数
实际上,类型类的常见实现将这种多态的x
作为一个函数来实现
x :: NumDict a -> a
其中上面的NumDict a
参数由编译器自动添加,并携带有关a
是Num
类型的信息,包括如何执行加法,如何解释a
中的整数文本,等等。这称为“字典传递”实现
因此,多次使用多态x
确实相当于多次调用函数,导致重新计算。为了避免这种情况,Haskell引入了(可怕的)单态限制,迫使x
成为单态。MR不是一个完美的解决方案,在某些情况下可能会产生一些令人惊讶的类型错误
为了缓解这个问题,在GHCi中默认禁用MR,因为在GHCi中,我们不太关心性能——可用性在那里更重要。但是,正如您所发现的那样,这会导致重新计算。我认为值得一提的是正在进行的字典传递。