2010-07-13 31 views
26

Tôi đang cố gắng để hiểu một điều cụ thể về module ocaml và biên soạn của họ:Redundancy trong khai báo kiểu OCaml (ml/MLI)

là tôi buộc phải redeclare loại đã tuyên bố trong một .mli bên trong .ml triển khai cụ thể?

Chỉ cần đưa ra một ví dụ:

(* foo.mli *) 
type foobar = Bool of bool | Float of float | Int of int 

(* foo.ml *) 
type baz = foobar option 

này, theo cách thông thường của tôi về suy nghĩ về giao diện/triển khai, nên ok nhưng nó nói

Error: Unbound type constructor foobar

trong khi cố gắng để biên dịch với

ocamlc -c foo.mli 
ocamlc -c foo.ml 

Tất nhiên lỗi sẽ biến mất nếu tôi khai báo foobar bên trong foo.ml quá nhưng có vẻ như một cách phức tạp vì tôi phải giữ mọi thứ được đồng bộ hóa trên mọi thay đổi.

Có cách nào để tránh sự thừa này hoặc tôi buộc phải redeclare các loại mỗi lần?

Cảm ơn trước

Trả lời

15

OCaml cố gắng buộc bạn tách giao diện (.mli) khỏi việc triển khai (.ml. Hầu hết thời gian, đây là một điều tốt; vì giá trị, bạn xuất bản loại trong giao diện và giữ mã trong Bạn có thể nói rằng OCaml đang thi hành một số lượng trừu tượng nhất định (các giao diện phải được xuất bản; không có mã nào trong các giao diện).

Đối với các loại, rất thường xuyên, việc triển khai giống như giao diện: cả hai đều cho biết loại có một biểu diễn cụ thể (và có lẽ là khai báo kiểu là sinh sản). Ở đây, có thể không có trừu tượng, bởi vì người triển khai không có bất kỳ thông tin nào về loại mà anh ta không muốn xuất bản. (Ngoại lệ về cơ bản là khi bạn khai báo một kiểu trừu tượng.)

Một cách để xem xét là giao diện đã chứa đủ thông tin để ghi thực hiện. Với giao diện type foobar = Bool of bool | Float of float | Int of int, chỉ có một triển khai có thể có. Vì vậy, không viết một thực hiện!

Thành ngữ phổ biến là có một mô-đun dành riêng cho việc khai báo loại và làm cho nó chỉ có một .mli. Vì các kiểu không phụ thuộc vào các giá trị, mô-đun này thường xuất hiện rất sớm trong chuỗi phụ thuộc. Hầu hết các công cụ biên dịch đối phó tốt với điều này; ví dụ ocamldep sẽ làm điều đúng. (Đây là một lợi thế so với việc chỉ có một .ml.)

Giới hạn của phương pháp này là khi bạn cũng cần một vài định nghĩa mô-đun ở đây và ở đó. (Ví dụ điển hình là xác định loại foo, sau đó là mô-đun OrderedFoo : Map.OrderedType với type t = foo, sau đó khai báo loại tiếp theo liên quan đến 'a Map.Make(OrderedFoo).t.) Chúng không thể được đặt trong tệp giao diện. Đôi khi có thể chấp nhận các định nghĩa của bạn thành nhiều phần, trước tiên là một loạt các loại (types1.mli), sau đó là một mô-đun (mod1.mlimod1.ml), sau đó nhiều loại (types2.mli). Các thời điểm khác (ví dụ: nếu định nghĩa đệ quy), bạn phải sống với một số .ml mà không cần .mli hoặc trùng lặp.

14

Vâng, bạn buộc phải redeclare loại. Những cách duy nhất xung quanh nó mà tôi biết là

  • Không sử dụng tệp .mli; chỉ phơi bày mọi thứ mà không có giao diện. Ý tưởng khủng khiếp.

  • Sử dụng công cụ lập trình biết chữ hoặc bộ tiền xử lý khác để tránh sao chép khai báo giao diện trong Nguồn thực. Đối với các dự án lớn, chúng tôi làm điều này trong nhóm của mình.

Đối với các dự án nhỏ, chúng tôi chỉ cần khai báo kiểu trùng lặp. Và càu nhàu về nó.

+0

Tôi không nghĩ rằng nên có bất kỳ hạn chế nào trong việc cho phép tệp '.ml' suy ra các loại được giải mã trong' .mli'. Từ những gì tôi hiểu thực hiện __forces redundancy__ thực tế nhưng cũng __the hai chữ ký phải bằng nhau vì vậy điều này có hiệu quả tăng gấp đôi cùng một tờ khai. Đó là lý do tại sao tôi nghĩ rằng nó nên được nhận thức của những tuyên bố mà không cần phải sao chép và dán chúng. Các thuật toán suy luận loại sẽ không bị vấn đề theo tôi. – Jack

+3

Nó không hoàn toàn buộc dự phòng cũng không yêu cầu chữ ký giống hệt nhau, chỉ cần khai báo trong tệp ml phải bằng hoặc cụ thể hơn khai báo mli. Điểm mli là để xác định những gì có thể nhìn thấy trong giao diện, vì vậy bạn có thể chọn không để lộ loại (trong trường hợp nó không có trong tập tin mli) hoặc bạn có thể chọn để lộ rằng có một loại, nhưng không phải như thế nào nó được sử dụng (trong trường hợp này các khai báo kiểu khác nhau). Tất nhiên trong tình huống của bạn nó sẽ có ý nghĩa cho trình biên dịch để chỉ giả định loại kể từ khi nó được xác định đầy đủ trong mli. –

+3

@Niki không có dự phòng buộc trong các khai báo * value * (tùy chọn trong .ml anyway), và trong thực tế đó là nơi "ít nhất là cụ thể như" đi kèm. Nhưng trong 99% các trường hợp * loại khai báo * được khai báo trong một giao diện giống hệt với định nghĩa của loại trong việc triển khai. Điều này là dư thừa, và gây khó chịu, nhưng với tư cách là một nhà thiết kế ngôn ngữ, tôi đã suy nghĩ rất kỹ về vấn đề này và tôi đã không đưa ra một đề nghị mà tôi cho rằng cả hai đều là nguyên tắc và tốt hơn đáng kể so với OCaml. –

12

Bạn có thể để ocamlc tạo ra các tập tin MLI cho bạn từ các tập tin ml:

ocamlc -i some.ml > some.mli 
3

Nói chung, có, bạn được yêu cầu lặp lại trong các loại.

Bạn có thể thực hiện việc này, tuy nhiên, với Camlp4 và tiện ích mở rộng cú pháp pa_macro (gói findlib: camlp4.macro). Nó định nghĩa, trong số những thứ khác, và BAO GỒM xây dựng. Bạn có thể sử dụng nó để định nghĩa các định nghĩa kiểu phổ biến vào một tệp riêng biệt và bao gồm tệp đó trong cả hai tệp .ml.mli. Tôi chưa thấy điều này được thực hiện trong một dự án OCaml được triển khai, tuy nhiên, vì vậy tôi không biết rằng nó sẽ đủ điều kiện như là thực hành được khuyến cáo, nhưng có thể.

Giải pháp lập trình biết chữ, tuy nhiên, là IMO rõ ràng hơn.

-3

Không, trong tệp mli, chỉ cần nói "nhập foobar". Điều này sẽ làm việc.

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