は式を WHNF に還元:sprint
しないことに注意してください。もしそうなら、以下はむしろ与えるでしょう: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
これは、生成されたコードがまだ type の実際の型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#
。