Perhatikan bahwa :sprinttidak tidak mengurangi ekspresi untuk WHNF. Jika ya, maka yang berikut akan memberi 4daripada _:
Prelude> let four = 2 + 2 :: Int
Prelude> :sprint four
four = _
Sebaliknya, :sprintmengambil nama penjilidan, melintasi representasi internal dari nilai penjilidan, dan menunjukkan bagian yang sudah "dievaluasi" (yaitu, bagian yang merupakan konstruktor) sambil menggunakan _sebagai penampung untuk barang yang tidak dievaluasi (yaitu, fungsi malas yang ditangguhkan panggilan). Jika nilainya sama sekali tidak dievaluasi, evaluasi tidak akan dilakukan, bahkan untuk WHNF. (Dan jika nilainya sepenuhnya dievaluasi, Anda akan mendapatkannya, bukan hanya WHNF.)
Apa yang Anda amati dalam percobaan adalah kombinasi tipe numerik polimorfik versus monomorfik, representasi internal berbeda untuk string literal versus daftar karakter eksplisit, dll. Pada dasarnya, Anda mengamati perbedaan teknis dalam cara ekspresi literal yang berbeda dikompilasi ke kode byte. Jadi, menafsirkan detail implementasi ini sebagai sesuatu yang berkaitan dengan WHNF akan membingungkan Anda. Secara umum, Anda harus menggunakan:sprint sebagai alat debugging saja, bukan sebagai cara untuk belajar tentang WHNF dan semantik evaluasi Haskell.
Jika Anda benar-benar ingin memahami apa :sprintyang dilakukan, Anda dapat menyalakan beberapa flag di GHCi untuk melihat bagaimana ekspresi sebenarnya ditangani dan, jadi, akhirnya dikompilasi ke bytecode:
> :set -ddump-simpl -dsuppress-all -dsuppress-uniques
Setelah ini, kita dapat melihat alasan Anda intlistmemberi _:
> 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>)
[])
Anda dapat mengabaikan panggilan returnIOluar :dan, dan berkonsentrasi pada bagian yang dimulai dengan((\ @ a $dNum -> ...
Berikut $dNumadalah kamus untuk Numbatasannya. Ini berarti bahwa kode yang dihasilkan belum menyelesaikan tipe aktual adalam jenis tersebut Num a => [[a]], sehingga seluruh ekspresi masih direpresentasikan sebagai pemanggilan fungsi yang mengambil (kamus untuk) Numjenis yang sesuai . Dengan kata lain, ini adalah kesalahan yang tidak dievaluasi, dan kami mendapatkan:
> :sprint intlist
_
Di sisi lain, tentukan jenisnya sebagai Int, dan kodenya benar-benar berbeda:
> let intlist = [[1::Int,2],[2,3]]
==================== Simplified expression ====================
returnIO
(: ((: (: (I# 1#) (: (I# 2#) []))
(: (: (I# 2#) (: (I# 3#) [])) []))
`cast` <Co:6>)
[])
dan begitu pula :sprinthasilnya:
> :sprint intlist
intlist = [[1,2],[2,3]]
Demikian pula, string literal dan daftar karakter yang eksplisit memiliki representasi yang sangat berbeda:
> 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>)
[])
dan perbedaan dalam :sprintoutput mewakili artefak yang bagian dari ekspresi GHCi dianggap dievaluasi ( :konstruktor eksplisit ) versus tidak dievaluasi (thunks unpackCString#).