Hãy bắt đầu bằng một ngôn ngữ tổng thể như Agda. Sau đó, như gallais tuyên bố, điều này chỉ có ý nghĩa nếu theo "loại trống", bạn có nghĩa là loại đơn vị, tức là bộ dữ liệu 0-ary, có chính xác một giá trị. Loại trống có thể được coi là loại tổng 0 trường hợp và không có giá trị nào cả. Trong Agda, bạn có thể dễ dàng chứng minh rằng nó Unit -> A
là đẳng cấu A
. Theo nghĩa đó, bạn có thể coi chúng giống nhau, mặc dù chúng vẫn không giống nhau theo nghĩa đen. Tôi không thể, ví dụ, làm một phân tích trường hợp trên Unit -> Bool
và tôi cũng không thể áp dụng True : Bool
cho bất cứ điều gì như là một chức năng.
Câu chuyện cho Haskell khá khác biệt. () -> A
và A
là các loại không đẳng cấu. Đặc biệt, () -> ()
có bốn giá trị, trong khi ()
chỉ có 2. Bốn observationally biệt giá trị undefined
, \_ -> undefined
, \x -> x
, \_ -> ()
. Vì vậy, ()
thực sự không phải là một loại đơn vị, theo nghĩa là có chính xác một chức năng ()
. (Trong Agda, mặt khác, chúng ta có thể chứng minh rằng nếu x : Unit
và y : Unit
, thì chúng bằng nhau [theo định nghĩa vì vậy nếu chúng ta xác định Unit
bằng record
cú pháp trái ngược với data
cú pháp]. Điều đó có nghĩa là, Unit
chỉ có một giá trị. Unit
và A -> Unit
là đẳng cấu cho bất kỳ A
.)
Trong thực tế, một loại "trống" như Void
được định nghĩa data Void
gần giống như một loại đơn vị theo nghĩa này. Void
chỉ có một giá trị, nhưng Void -> Void
vẫn có hai. Trong thực tế, mọi loại hàm A -> B
, có ít nhất hai giá trị riêng biệt quan sát được, đó là undefined
và \_ -> undefined
. Do đó, Haskell không có đơn vị thực sự hoặc loại khoảng trống.
Rất nhiều điều này là do Haskell là một ngôn ngữ không nghiêm ngặt và bị bực tức bởi sự tồn tại của seq
(và tương đương của nó). Ví dụ, sự khác biệt giữa undefined
và \_ -> undefined
chỉ có thể được nhìn thấy với seq
. Nếu chúng ta loại bỏ seq
và tương đương với Haskell, thì Void
sẽ phục vụ như một loại đơn vị, tuy nhiên, trớ trêu thay, vẫn không phải là một loại trống.
Thông thường, khi mọi người nói về những điều như vậy trong Haskell, họ ngầm giả vờ rằng Haskell là một ngôn ngữ cư xử tốt hơn nó. Đó là, họ cho rằng đáy không tồn tại cho mục đích của họ, tức là bạn đang làm việc trong một ngôn ngữ tổng thể như Agda. Đối với mục đích thiết kế mã của bạn, điều này thường là đầy đủ; nó không phổ biến mà chúng ta quan tâm hoặc mong đợi đáy. Những khác biệt này có thể trở nên quan trọng nếu chúng ta đang làm một cái gì đó như lập trình vòng tròn hoặc nếu đảm bảo an toàn cho chương trình của chúng tôi dựa vào các thuộc tính này, ví dụ: một hàm không bao giờ có thể được gọi nếu nó có kiểu trống như miền của nó.