Câu hỏi tuyệt vời!
Có một số khác biệt chính.
Đại diện
- Một
newtype
đảm bảo rằng dữ liệu của bạn sẽ có cùng một đại diện chính xác trong thời gian chạy, như kiểu mà bạn bọc.
- Trong khi
data
tuyên bố một cấu trúc dữ liệu hoàn toàn mới trong thời gian chạy.
Vì vậy, điểm quan trọng ở đây là cấu trúc cho newtype
được đảm bảo sẽ bị xóa trong thời gian biên dịch.
Ví dụ:
newtype Book = Book (Int, Int)
Lưu ý làm thế nào nó có đại diện chính xác như a (Int,Int)
, vì hàm Book
tạo bị xóa.
data Book = Book (Int, Int)
Có một nhà Book
xây dựng bổ sung không có mặt trong newtype
.
data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int
Không có con trỏ! Hai Int
trường là các trường có kích thước từ không có hộp trong hàm Book
tạo.
Các kiểu dữ liệu đại số
Do điều này cần phải xóa hàm tạo, nên newtype
chỉ hoạt động khi gói một kiểu dữ liệu với một hàm tạo duy nhất . Không có khái niệm về các kiểu mới "đại số". Đó là, bạn không thể viết một loại mới tương đương với, nói,
data Maybe a = Nothing
| Just a
vì nó có nhiều hơn một constructor. Bạn cũng không thể viết
newtype Book = Book Int Int
Nghiêm khắc
Việc các nhà xây dựng bị xóa dẫn đến một số khác biệt rất tinh tế về mức độ nghiêm ngặt giữa data
và newtype
. Cụ thể, data
giới thiệu một loại "nâng", về cơ bản, có nghĩa là nó có một cách bổ sung để đánh giá giá trị dưới cùng. Vì không có hàm tạo bổ sung nào trong thời gian chạy với newtype
, thuộc tính này không giữ.
Đó là con trỏ phụ trong Book
để (,)
xây dựng cho phép chúng ta đặt một giá trị đáy trong.
Kết quả là, newtype
và data
có các thuộc tính nghiêm ngặt hơi khác nhau, như được giải thích trong bài viết wiki Haskell .
Bỏ hộp
Không có ý nghĩa để bỏ hộp các thành phần của a newtype
, vì không có hàm tạo. Trong khi nó là hoàn toàn hợp lý để viết:
data T = T {-# UNPACK #-}!Int
mang lại một đối tượng thời gian chạy với một hàm T
tạo và một Int#
thành phần. Bạn chỉ cần có một trần Int
với newtype
.
Tài liệu tham khảo :