Lưu ý rằng :sprint
không không giảm một biểu thức để WHNF. Nếu có, thì sau đây sẽ cung cấp 4
thay vì _
:
Prelude> let four = 2 + 2 :: Int
Prelude> :sprint four
four = _
Thay vào đó, :sprint
lấy tên của một ràng buộc, đi qua biểu diễn bên trong của giá trị của ràng buộc và hiển thị "các phần được đánh giá" (nghĩa là các phần là các hàm tạo) trong khi sử dụng _
như một trình giữ chỗ cho các hàm không được đánh giá (nghĩa là hàm lười biếng bị treo các cuộc gọi). Nếu giá trị hoàn toàn không được đánh giá, sẽ không có đánh giá nào được thực hiện, thậm chí không phải với WHNF. (Và nếu giá trị được đánh giá hoàn toàn, bạn sẽ nhận được giá trị đó, không chỉ WHNF.)
Những gì bạn đang quan sát trong các thử nghiệm của mình là sự kết hợp của các kiểu số đa hình và đơn hình, các cách biểu diễn bên trong khác nhau cho các chuỗi ký tự so với các danh sách rõ ràng của các ký tự, v.v. Vì vậy, việc diễn giải các chi tiết triển khai này có liên quan đến WHNF sẽ khiến bạn bối rối. Nói chung, bạn chỉ nên sử dụng :sprint
như một công cụ gỡ lỗi, không phải là cách để tìm hiểu về WHNF và ngữ nghĩa của đánh giá Haskell.
Nếu bạn thực sự muốn hiểu những gì :sprint
đang làm, bạn có thể bật một vài cờ trong GHCi để xem cách các biểu thức thực sự được xử lý và, do đó, cuối cùng được biên dịch thành mã byte:
> :set -ddump-simpl -dsuppress-all -dsuppress-uniques
Sau này, chúng ta có thể thấy lý do bạn intlist
đưa ra _
:
> 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>)
[])
Bạn có thể bỏ qua cuộc gọi returnIO
bên ngoài :
và tập trung vào phần bắt đầu bằng((\ @ a $dNum -> ...
Đây $dNum
là từ điển cho các Num
ràng buộc. Điều này có nghĩa là mã được tạo chưa giải quyết loại thực tế a
trong loại Num a => [[a]]
, do đó toàn bộ biểu thức vẫn được biểu diễn dưới dạng một lệnh gọi hàm lấy (từ điển cho) một Num
loại thích hợp . Nói cách khác, đó là một thunk không được đánh giá cao và chúng tôi nhận được:
> :sprint intlist
_
Mặt khác, chỉ định loại là Int
và mã hoàn toàn khác nhau:
> let intlist = [[1::Int,2],[2,3]]
==================== Simplified expression ====================
returnIO
(: ((: (: (I# 1#) (: (I# 2#) []))
(: (: (I# 2#) (: (I# 3#) [])) []))
`cast` <Co:6>)
[])
và :sprint
đầu ra cũng vậy:
> :sprint intlist
intlist = [[1,2],[2,3]]
Tương tự, các chuỗi ký tự và danh sách các ký tự rõ ràng có các cách biểu diễn hoàn toàn khác nhau:
> 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>)
[])
và sự khác biệt trong :sprint
đầu ra đại diện cho các tạo phẩm trong đó các phần của biểu thức mà GHCi xem xét được đánh giá (các hàm tạo rõ ràng :
) so với không đánh giá (các unpackCString#
thunks).