Perhatikan bahwa :sprint
tidak tidak mengurangi ekspresi untuk WHNF. Jika ya, maka yang berikut akan memberi 4
daripada _
:
Prelude> let four = 2 + 2 :: Int
Prelude> :sprint four
four = _
Sebaliknya, :sprint
mengambil 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 :sprint
yang 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 intlist
memberi _
:
> 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 returnIO
luar :
dan, dan berkonsentrasi pada bagian yang dimulai dengan((\ @ a $dNum -> ...
Berikut $dNum
adalah kamus untuk Num
batasannya. Ini berarti bahwa kode yang dihasilkan belum menyelesaikan tipe aktual a
dalam jenis tersebut Num a => [[a]]
, sehingga seluruh ekspresi masih direpresentasikan sebagai pemanggilan fungsi yang mengambil (kamus untuk) Num
jenis 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 :sprint
hasilnya:
> :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 :sprint
output mewakili artefak yang bagian dari ekspresi GHCi dianggap dievaluasi ( :
konstruktor eksplisit ) versus tidak dievaluasi (thunks unpackCString#
).