我偶然发现了一些令人讨厌的东西。我知道haskell可用于弱头正常形式(WHNF),而且我知道这是什么。将以下代码键入ghci(据我所知,我正在使用命令:sprint,将表达式简化为WHNF。):
let intlist = [[1,2],[2,3]]
:sprint intlist
给intlist = _
这对我来说完全有意义。
let stringlist = ["hi","there"]
:sprint stringlist
给予stringlist = [_,_]
这已经使我感到困惑。但是然后:
let charlist = [['h','i'], ['t','h','e','r','e']]
:sprint charlist
令人惊讶地给出charlist = ["hi","there"]
据我了解,Haskell,字符串不过是字符列表,这似乎可以通过检查类型"hi" :: [Char]
和['h','i'] :: [Char]
来确认。
我感到困惑,因为根据我的理解,以上所有三个示例大致相同(列表列表),因此应简化为相同的WHNF,即_。我想念什么?
谢谢
请注意,:sprint
会不是将表达式简化为WHNF。如果确实如此,则以下内容将给出4
而不是_
:
Prelude> let four = 2 + 2 :: Int
Prelude> :sprint four
four = _
相反,:sprint
采用绑定的名称,遍历绑定值的内部表示,并显示使用“ _
作为未评估的占位符时已被评估的部分”(即构成构造的部分)重击(即暂停的惰性函数调用)。如果该值未完全评估,则不会进行评估,甚至不会对WHNF进行评估。 (而且,如果对值进行了完全评估,您将得到,而不仅仅是WHNF。)
[您在实验中观察到的是多态与单态数字类型的组合,字符串文字的不同内部表示形式与显式字符列表等的组合。基本上,您观察到在将不同的文字表达形式编译为字节时存在技术差异。码。因此,将这些实现细节解释为与WHNF有关会使您感到无望。通常,您仅应将:sprint
用作调试工具,而不应将其用作了解WHNF和Haskell评估语义的方式。
如果您真的想了解:sprint
在做什么,则可以在GHCi中打开一些标志来查看表达式的实际处理方式,并最终将其编译为字节码:
> :set -ddump-simpl -dsuppress-all -dsuppress-uniques
此后,我们可以看到您的intlist
给出_
的原因:
> let intlist = [[1,2],[2,3]]
==================== Simplified expression ====================
returnIO
(: ((\ @ a $dNum ->
: (: (fromInteger $dNum 1) (: (fromInteger $dNum 2) []))
(: (: (fromInteger $dNum 2) (: (fromInteger $dNum 3) [])) []))
`cast` <Co:10>)
[])
您可以忽略returnIO
和外部:
调用,而将注意力放在以((\ @ a $dNum -> ...
开头的部分上>
这里$dNum
是Num
约束的字典。这意味着生成的代码尚未将类型a
解析为实际的类型Num a => [[a]]
,因此整个表达式仍表示为函数调用,该函数采用适当的Num
类型。换句话说,这是一个未经评估的重击,我们得到:
> :sprint intlist _
另一方面,将类型指定为
Int
,并且代码完全不同:
> let intlist = [[1::Int,2],[2,3]] ==================== Simplified expression ==================== returnIO (: ((: (: (I# 1#) (: (I# 2#) [])) (: (: (I# 2#) (: (I# 3#) [])) [])) `cast` <Co:6>) [])
:sprint
输出也是:
> :sprint intlist intlist = [[1,2],[2,3]]
类似地,文字字符串和显式字符列表具有完全不同的表示形式:
> let stringlist = ["hi", "there"] ==================== Simplified expression ==================== returnIO (: ((: (unpackCString# "hi"#) (: (unpackCString# "there"#) [])) `cast` <Co:6>) []) > let charlist = [['h','i'], ['t','h','e','r','e']] ==================== Simplified expression ==================== returnIO (: ((: (: (C# 'h'#) (: (C# 'i'#) [])) (: (: (C# 't'#) (: (C# 'h'#) (: (C# 'e'#) (: (C# 'r'#) (: (C# 'e'#) []))))) [])) `cast` <Co:6>) [])
[
:sprint
输出中的差异表示GHCi认为表达式的哪些部分被评估(显式:
构造函数)与未评估(unpackCString#
粗体)的伪影。