Saya telah menemukan beberapa hal yang menjengkelkan. Saya tahu bahwa haskell bekerja dengan bentuk normal kepala lemah (WHNF) dan saya tahu apa ini. Mengetik kode berikut ke dalam ghci (saya menggunakan perintah: sprint yang mengurangi ekspresi menjadi WHNF untuk pengetahuan saya.):
let intlist = [[1,2],[2,3]]
:sprint intlist
memberikan intlist = _
ini sangat masuk akal bagi saya.
let stringlist = ["hi","there"]
:sprint stringlist
memberi stringlist = [_,_]
Ini sudah membingungkan saya. Tapi kemudian:
let charlist = [['h','i'], ['t','h','e','r','e']]
:sprint charlist
secara mengejutkan memberi charlist = ["hi","there"]
Sejauh yang saya mengerti Haskell, string tidak lain adalah daftar karakter, yang tampaknya dikonfirmasi dengan memeriksa jenis "hi" :: [Char]
dan ['h','i'] :: [Char]
.
Saya bingung, karena dalam pemahaman saya ketiga contoh di atas kurang lebih sama (daftar daftar) dan karenanya harus dikurangi menjadi WHNF yang sama, yaitu _. Apa yang saya lewatkan?
Terima kasih
"bla"
dan['b','l','a']
akan keluar secara berbeda."bla"
bisa kelebihan beban, tetapi['b','l','a']
dikenal sebagaiString
/[Char]
?['b', 'l', 'a']
bisa juga kelebihan beban , dan juga"bla"
hanya kelebihan beban jika-XOverloadedStrings
dihidupkan.Jawaban:
Perhatikan bahwa
:sprint
tidak tidak mengurangi ekspresi untuk WHNF. Jika ya, maka yang berikut akan memberi4
daripada_
: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:Setelah ini, kita dapat melihat alasan Anda
intlist
memberi_
:Anda dapat mengabaikan panggilan
returnIO
luar:
dan, dan berkonsentrasi pada bagian yang dimulai dengan((\ @ a $dNum -> ...
Berikut
$dNum
adalah kamus untukNum
batasannya. Ini berarti bahwa kode yang dihasilkan belum menyelesaikan tipe aktuala
dalam jenis tersebutNum 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:Di sisi lain, tentukan jenisnya sebagai
Int
, dan kodenya benar-benar berbeda:dan begitu pula
:sprint
hasilnya:Demikian pula, string literal dan daftar karakter yang eksplisit memiliki representasi yang sangat berbeda:
dan perbedaan dalam
:sprint
output mewakili artefak yang bagian dari ekspresi GHCi dianggap dievaluasi (:
konstruktor eksplisit ) versus tidak dievaluasi (thunksunpackCString#
).sumber