2012-03-19 27 views
12

Tôi đang thử nghiệm ngôn ngữ mô-đun của OCaml (3.12.1), xác định các functors và chữ ký cho các mô-đun và cứ như vậy, chủ yếu là theo các ví dụ từ Chapter 2 of the OCaml manual và tôi đã tình cờ gặp , trên một tình huống mà dường như mô hình tinh thần của tôi về cách functors và mô-đun chữ ký làm việc là thiếu sót. Tôi đã cố gắng thu hẹp tình huống mà tôi gặp phải với số lượng mã ngắn nhất có thể, do đó, không hỏi những gì tôi đang cố gắng hoàn thành, đây là một ví dụ hoàn toàn giả vờ để chứng minh tính năng OCaml được đề cập.OCaml functors :: hành vi truy cập trực quan

Vì vậy, chúng tôi có một hàm sĩ chỉ đơn giản cung cấp chức năng nhận dạng 'f' và được tham số bởi một mô-đun cung cấp loại thông số đầu vào của hàm đó. Ví dụ hoàn toàn giả tạo như tôi đã nói.

module type SOMETYPE = sig type t end ;; 
module Identity = functor (Type: SOMETYPE) -> struct let f (x: Type.t) = x end ;; 

Given ở trên, chúng tôi tiến hành để xác định một mô-đun cung cấp các loại int:

module IntType = struct type t = int end ;; 

.. và sau đó chúng tôi sử dụng các functor để tạo ra một mô-đun cho hàm int sắc:

module IdentityInt = Identity(IntType) ;;      

chắc chắn đủ các module được tạo ra và f chức năng cư xử của mình như mong đợi:

#IdentityInt.f(3) + 10 ;; 
- : int = 13 

Mô hình tinh thần của các functors là các chức năng lấy mô-đun làm đầu vào và các mô-đun trả về dường như đang phục vụ chúng ta cho đến nay. Các Identity functor mong đợi như tham số đầu vào một mô-đun chữ ký (loại mô-đun) SOMETYPE, và thực sự mô-đun chúng tôi cung cấp (IntType) có chữ ký chính xác và do đó mô-đun đầu ra hợp lệ được sản xuất (IdentityInt) có chức năng hoạt động như mong đợi.

Bây giờ đến phần không trực quan. Điều gì sẽ xảy ra nếu chúng ta muốn làm rõ rằng module được cung cấp IntType thực sự là kiểu mô-đun SOMETYPE. Như trong:

module IntType : SOMETYPE = struct type t = int end ;; 

và sau đó tạo ra mô-đun đầu ra của functor theo cùng một cách như trước:

module IdentityInt = Identity(IntType) ;; 

... chúng ta hãy cố gắng sử dụng f chức năng của các module mới được tạo ra:

IdentityInt.f 0 ;; 

Whereupon REPL than phiền với:

"Error: This expression [the value 0] has type int but an expression was expected of type IntType.t." 

Làm cách nào để cung cấp thông tin loại thừa nhưng đúng loại vi phạm mã? Ngay cả trong trường hợp Một mô-đun functor Danh tính phải xử lý mô-đun IntType là loại SOMETYPE. Vậy làm cách nào để khai báo rõ ràng IntType là loại SOMETYPE mang lại kết quả khác?

+0

Có mục đích là 'module IntType' thứ hai thiếu phần' = int' không? – Ptival

+0

Không, đó là lỗi đánh máy trên biểu mẫu dán bản sao REPL của tôi. Module IntType thứ hai đọc chính xác: 'module IntType: SOMETYPE = struct type t = int end' và bạn nhận được chính xác kết quả tương tự mà tôi mô tả ở trên. Tôi cũng sẽ chỉnh sửa bài đăng để tránh bất kỳ sự hiểu lầm nào. –

Trả lời

10

Cấu trúc : khác với ngôn ngữ chính và ngôn ngữ mô-đun. Trong ngôn ngữ cốt lõi, nó là một cấu trúc chú thích. Ví dụ: ((3, x) : 'a * 'a list) ràng buộc biểu thức có một số loại là phiên bản 'a * 'a list; vì phần tử đầu tiên của cặp là số nguyên, let (a, b) = ((3, x) : 'a * 'a list) in a + 1 được nhập tốt. Cấu trúc : trên các mô-đun không có nghĩa là điều này.

Cấu trúc M : Scon dấu mô-đun M vào chữ ký S. Đây là một con dấu mờ: chỉ có thông tin được đưa ra trong chữ ký S vẫn có sẵn khi nhập sử dụng M : S. Khi bạn viết module IntType : SOMETYPE = struct type t end, đây là một cú pháp thay thế cho

module IntType = (struct type t end : SOMETYPE) 

Kể từ khi loại hình trường t trong SOMETYPE còn lại không xác định, IntType có một loại lĩnh vực trừu tượng t: loại IntType là một loại mới, được tạo ra bởi định nghĩa này.

Nhân tiện, bạn có thể có nghĩa là module IntType = (struct type t = int end : SOMETYPE); nhưng một trong hai cách, IntType.t là một loại trừu tượng.

Nếu bạn muốn chỉ định rằng một mô-đun có chữ ký nhất định trong khi để lại một số loại được hiển thị, bạn cần thêm sự bình đẳng rõ ràng cho các loại này. Không có cấu trúc nào để thêm tất cả các điểm cân bằng, vì việc áp dụng chữ ký cho một mô-đun thường có nghĩa là để ẩn thông tin. Vì lợi ích của sự đơn giản, ngôn ngữ chỉ cung cấp một cấu trúc niêm phong sinh tổng hợp này.Nếu bạn muốn sử dụng chữ ký được xác định SOMETYPE và duy trì tính minh bạch của các loại t, thêm một rào cản đối với chữ ký:

module IntType = (struct type t = int end : SOMETYPE with type t = int) 
+0

Vâng, nó là 'module IntType = (struct type t = int end: SOMETYPE)' Ý tôi là; đó là một lỗi sao chép từ REPL của tôi (tôi đã chỉnh sửa bài đăng để sửa nó). Tuy nhiên, như bạn nói, người ta nhận được kết quả tương tự. Bây giờ tôi hiểu cấu trúc ':' trong các mô-đun không phải là một chú thích nhưng ẩn thông tin thay vì mặc dù tôi không chắc chắn rằng tôi hoàn toàn đánh giá cao tất cả các minutiae. –

7

Nếu bạn nhìn vào chữ ký suy ra khi bạn không viết một cái gì đó một cách rõ ràng:

# module IntType = struct type t = int end ;; 
module IntType : sig type t = int end 

Chữ ký tiết lộ rằng t là một int.Chữ ký của bạn, ngược lại:

# module IntType : SOMETYPE = struct type t = int end ;; 
module IntType : SOMETYPE 

thực sự là:

# module IntType : sig type t end = struct type t = int end ;; 
module IntType : sig type t end 

này dường như để giải quyết vấn đề của bạn:

# module IntType : (SOMETYPE with type t = int) = struct type t = int end ;; 
module IntType : sig type t = int end 
# module IdentityInt = Identity(IntType) ;; 
module IdentityInt : sig val f : IntType.t -> IntType.t end 
# IdentityInt.f 0 ;; 
- : IntType.t = 0 

(bạn không cần dấu ngoặc, nhưng họ giúp phân tích tinh thần). Về cơ bản, bạn vạch trần thực tế rằng t là một int với chữ ký của bạn. Vì vậy, OCaml biết sự bình đẳng IntType.t = int.

Để biết thêm chi tiết về nội bộ, tôi sẽ để nó cho những người hiểu biết nhiều hơn.

5

Khi bạn viết:

module IntType : SOMETYPE = struct type t = int end ;; 

Bạn đang kìm hãm chữ ký của InType để được chính xác SOMETYPE. Điều này có nghĩa là, ví dụ, kiểu t hiện đang trở thành một kiểu trừu tượng (mà việc thực hiện không được biết đến với typer).

Vì vậy, IdentityInt.f loại vẫn là IntType.t -> IntType.t, nhưng, bằng cách sử dụng ràng buộc chữ ký, bạn đã loại bỏ phương trình IntType.t = int một cách rõ ràng khỏi kiến ​​thức typer. Thông báo lỗi bạn nhận được sẽ cho bạn biết chính xác điều đó.

5

lỗi chìa khóa của bạn đã ở đây:

mô-đun IntType: SOMETYPE = struct loại t kết thúc ;;

Khi bạn gán chữ ký SOMETYPE, đó là bản ghi mờ và nhận dạng với int bị mất. Loại IntType.t hiện là loại trừu tượng.

Thay vào đó, bạn cần ghi chữ ký SOMETYPE with type t = int.

bảng điểm này cho thấy sự khác biệt:

# module type SOMETYPE = sig type t end;; 
module type SOMETYPE = sig type t end 
# module IntType : SOMETYPE with type t = int = struct type t = int end;; 
module IntType : sig type t = int end 
# module AbsType : SOMETYPE = struct type t = int end;;     
module AbsType : SOMETYPE 

Những vấn đề ngôn ngữ thiết kế xung quanh mô-đun và gán ghép cũng được bao gồm trong các nhà thiết kế chính của 1994 paper on modules, types, and separate compilation. Các phần toán học lông có thể được bỏ qua.

+0

Cảm ơn, nó thực sự 'module IntType: SOMETYPE = struct type t = int end ;;' mà tôi đã sử dụng (tôi đã thực hiện một lỗi sao chép từ REPL của tôi nhưng bây giờ đã cập nhật bài đăng). Tuy nhiên, người ta cũng nhận được kết quả tương tự. Kiểu 't' bị mất mặc dù được chỉ định và chỉ khi sử dụng cấu trúc bạn và các áp phích khác được đề xuất (cụ thể là' module IntType: SOMETYPE với kiểu t = int = struct type t = int end' bạn có nhận được kết quả mong đợi hay không. , theo quan điểm của tôi không chính xác trực quan nhất để nắm bắt khái niệm hoặc cú pháp và thay vào đó là hướng dẫn sử dụng OCaml –

+0

@Menelaos, ascription được nhiều người yêu thích của chúng tôi mô-đun guys.Những vấn đề này được chiếu sáng bằng giấy 1994 của Xavier Leroy từ POPL. đã thêm một liên kết vào câu trả lời của tôi –

+0

Rất cám ơn, chỉ cần tải xuống. –

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