2012-04-20 39 views
13

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?

+11

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). –

+0

... không chấp nhận? :) –

Trả lời

22

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 ab để 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.

+2

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? –

7

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.

+0

Đâ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! –

16

Giống như nói "tại sao chúng ta cần các lớp đố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" 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.

+0

Cảm ơn bạn đã giải thích chi tiết! –

Các vấn đề liên quan