Tôi là người mới đến Haskell và hiện đang trải qua Thế giới thực Haskell. Cuốn sách nói rằng hàm tạo kiểu được sử dụng chỉ trong chữ ký kiểu trong khi hàm tạo giá trị được sử dụng trong mã thực tế. Nó cũng đưa ra một ví dụ về một tuyên bố cho thấy rằng các tên cho cả hai đều độc lập với nhau. Tại sao hai nhà xây dựng cần ở nơi đầu tiên, nếu chỉ một trong số chúng được sử dụng trong mã thực tế? Vì chúng ta sẽ không sử dụng hàm tạo kiểu trong mã thực tế, nên hàm tạo kiểu nào phục vụ?Tại sao có một hàm tạo giá trị ngoài hàm tạo kiểu trong Haskell?
Trả lời
Có thể tên có một chút gây hiểu lầm. A constructor kiểu đại diện cho tên của loại bạn đang khai báo. Chúng được gọi như vậy bởi vì chúng xây dựng các kiểu, không phải các giá trị: thực sự, được (có thể) tham số hóa trên các biến kiểu mà chúng định nghĩa một họ các kiểu. Chúng hoạt động giống như các mẫu của C++ và các Generics của Java. Trong data MyType a b = Constr a b
, MyType là một hàm tạo kiểu có hai loại a
và b
để tạo loại mới (MyType a b)
.
A hàm tạo giá trị là phần duy nhất bạn sẽ gọi là "hàm tạo" trong các ngôn ngữ khác (hướng đối tượng), vì bạn cần nó để tạo giá trị cho loại đó. Vì vậy, trong ví dụ trước, nếu bạn lấy hàm tạo giá trị Constr :: a -> b -> MyType a b
, bạn có thể tạo giá trị Constr "abc" 'd' :: MyType [Char] Char
.
Tôi có thể hỏi cách cải thiện câu trả lời của mình để loại bỏ câu trả lời đó không? Chuyện gì vậy? –
Một cách thuận tiện để có được trực giác về loại và giá trị là cựu là thời gian biên dịch giá trị trong khi sau này là thời gian chạy giá trị. Nói cách khác, Type constructors là các hàm tạo của các giá trị trong tập hợp các kiểu Haskell, với mục đích duy nhất là gõ chương trình của bạn vào thời gian biên dịch. Điều đó cũng có nghĩa là bạn không thể xây dựng một loại tại thời gian chạy, và bạn không thể xây dựng một giá trị tại thời gian biên dịch. Vì vậy, bởi vì bạn không thể phân nhánh rõ ràng vào thời gian chạy trên cơ sở giá trị kiểu (mặc dù bạn có thể ngầm với typeclasses), các hàm tạo kiểu hoàn toàn vô dụng như các đối tượng thời gian chạy và trong nhiều trường hợp hoàn toàn không có trong nhị phân cuối cùng. Ngược lại, bởi vì các hàm tạo giá trị cho phép xây dựng các giá trị trong tập hợp kiểu của chúng tại thời gian chạy, chúng hoàn toàn vô dụng như đối tượng thời gian biên dịch.
Vì thuộc tính đơn giản này, Gõ constructors và Value constructors có thể chia sẻ tên một cách rõ ràng.
Đây là câu trả lời đơn giản nhất để hiểu những người đến từ một nền tảng bắt buộc! –
Giống như nói "tại sao chúng ta cần các lớp và đối tượng nếu đối tượng là thứ duy nhất thực sự chạy?"
Hai loại nhà thầu thực hiện các công việc khác nhau. Loại nhà xây dựng đi trong chữ ký loại. Các hàm tạo giá trị đi trong mã runnable.
Trong trường hợp đơn giản nhất, một loại "hàm tạo" là chỉ là tên loại. Trong trường hợp đơn giản nhất, một kiểu chỉ có một hàm tạo giá trị. Vì vậy, bạn kết thúc với những thứ như
data Point = Point Int Int
Bạn có thể nói với chính mình "bây giờ tại sao các heck để tôi cần phải viết Point
hai lần?"
Nhưng bây giờ hãy xem xét một ví dụ ít tầm thường:
data Tree x = Leaf x | Branch (Tree x) (Tree x)
Đây Tree
là một constructor loại.Bạn cho nó một đối số kiểu, và nó "xây dựng" một kiểu. Vì vậy, Tree Int
là một loại, Tree String
là một loại khác, v.v. (Giống như các mẫu trong C++ hoặc generics trong Java hoặc Eiffel.)
Mặt khác, Leaf
là một hàm tạo giá trị. Với một giá trị, nó tạo ra một cây 1 nút. Vì vậy, Leaf 5
là giá trị Tree Int
, Leaf "banana"
là giá trị Tree String
, v.v.
Tương tự cho Branch
. Phải mất hai giá trị cây và xây dựng một nút cây với những cây như trẻ em. Ví dụ: Branch (Leaf 2) (Leaf 7)
là giá trị Tree Int
.
Cảm ơn bạn đã giải thích chi tiết! –
- 1. Hàm tạo chuỗi có giá trị rỗng
- 2. hàm tạo hoặc sao chép hàm tạo?
- 3. Cách tạo mảng Haskell từ hàm
- 4. Hàm tạo dữ liệu trong mẫu haskell
- 5. C#: Các kiểu generic có một hàm tạo?
- 6. gọi hàm tạo bản sao bên trong hàm tạo khác
- 7. Tại sao hàm tạo được sử dụng thay cho hàm?
- 8. Tại sao rõ ràng gọi một hàm tạo trong C++
- 9. Tại sao hàm tạo mặc định không xuất hiện cho các loại giá trị?
- 10. Tại sao hàm tạo bản sao này được gọi thay vì hàm tạo di chuyển?
- 11. Tại sao hàm tạo bản sao được gọi thay vì hàm tạo chuyển đổi?
- 12. Tại sao hàm Perl này trả về một giá trị?
- 13. Tại sao std :: các thể hiện hàm có một hàm tạo mặc định?
- 14. hàm tạo cơ sở gọi qua một giá trị
- 15. Sử dụng hàm tạo trong một cuộc gọi hàm?
- 16. Ví dụ về định nghĩa hàm trong hàm tạo dữ liệu của một kiểu mới
- 17. Giá trị hoặc hàm tạo không được xác định
- 18. Tại sao hàm tạo bản sao ngầm ẩn gọi hàm tạo bản sao lớp cơ sở và hàm tạo bản sao được xác định không?
- 19. Tại sao PHP không có hàm tạo mặc định?
- 20. Tôi có thể khởi tạo một lớp ẩn danh trong hàm tạo của lớp ngoài không?
- 21. Tại sao hàm tạo chỉ được gọi một lần?
- 22. Trong Go, làm cách nào để tạo một "hàm tạo" cho một kiểu có kiểu chuỗi ký tự?
- 23. Tại sao đặt hàm tạo của nguyên mẫu cho hàm tạo của nó?
- 24. Giá trị mặc định cho hàm tạo thuộc tính?
- 25. Một hàm tạo bản sao trong C++ là gì?
- 26. Một hàm tạo tại chỗ trong C++ là gì?
- 27. Cách khởi tạo một trường bit trong một hàm tạo
- 28. hàm tạo bản sao mẫu
- 29. Ẩn các hàm tạo kiểu dữ liệu
- 30. Hàm khởi tạo trống hoặc không có hàm tạo nào
Cụm từ "mã thực" không may, vì nó ngụ ý rằng bạn sẽ không sử dụng hàm tạo kiểu trong chương trình, khi các tác giả thực sự có nghĩa là các hàm tạo kiểu chỉ được sử dụng cho các chú thích kiểu. Điều này tương đương với việc bạn không cần từ khóa "int" hoặc "long" trong C vì bạn không sử dụng chúng trong mã thực tế (chúng chỉ được sử dụng trong các khai báo, không được tính là "mã thực "theo tiêu chuẩn này). –
... không chấp nhận? :) –