2013-02-11 42 views
8
type foo = A of int * int | B of (int * int) 

sự khác biệt giữa int * int(int * int) có là gì? Sự khác biệt duy nhất tôi thấy là trong kết hợp mẫu:int * int vs (int * int) trong OCaml loại tổng

let test_foo = function 
    | A (f, s) -> (f, s) 
    | B b -> b 

Nó chỉ là một đường cú pháp? Làm thế nào để bạn chọn cái nào để sử dụng? Có sự khác biệt về hiệu suất giữa hai hình thức này không?

+0

câu hỏi hay. – didierc

Trả lời

7

Vâng, có một sự khác biệt hiệu suất:

Trong bộ nhớ A (23, 42) sẽ chứa một thẻ xác định nó như một A và hai số nguyên 23 và 42. B (23, 42) sẽ chứa một thẻ xác định nó như là một B và một con trỏ đến một bộ chứa số nguyên 2342. Vì vậy, sẽ có thêm một cấp phát bộ nhớ khi tạo một B và một mức bổ sung của sự gián tiếp khi truy cập các giá trị riêng lẻ bên trong một B. Vì vậy, trong trường hợp bạn không thực sự sử dụng các đối số constructor như một bộ tuple, sử dụng A sẽ có ít chi phí hơn so với việc sử dụng B.

Mặt khác, hàm test_foo của bạn sẽ tạo một bộ mới mỗi khi được gọi với giá trị A, nhưng khi được gọi với giá trị B, nó sẽ trả về bộ nhớ đã tồn tại trong bộ nhớ. Vì vậy, test_foo là hoạt động rẻ hơn cho B so với số tiền là A. Vì vậy, nếu bạn sẽ sử dụng các đối số của hàm tạo như một bộ tuple và bạn sẽ làm như vậy nhiều lần cho cùng một giá trị, sử dụng B sẽ rẻ hơn. Vì vậy, nếu bạn định sử dụng các đối số hàm tạo như một bộ tuple, bạn nên sử dụng một hàm tạo lấy một bộ tuple vì bạn có thể lấy tuple bằng cách sử dụng mẫu khớp với ít mã hơn và vì nó sẽ tránh phải tạo tuples từ cùng một giá trị nhiều lần. Trong tất cả các trường hợp khác, không sử dụng bộ tuple là thích hợp hơn vì nó liên quan đến việc cấp phát bộ nhớ ít hơn và ít gián tiếp hơn.

+0

Vì vậy, không thể trích xuất thông tin từ 'A' mà không tạo ra tuple mới, phải không? – Stas

+0

@Stas Điều đó phụ thuộc vào ý của bạn là "trích xuất thông tin". Không thể lấy một tuple chứa dữ liệu 'A' mà không tạo một bộ dữ liệu mới. Nhưng chắc chắn có thể làm điều gì đó với dữ liệu của 'A' mà không tạo ra một bộ dữ liệu. Ví dụ như 'match foo với A (x, y) -> x + y' sẽ không tạo tuple và sẽ nhanh hơn mã tương đương bằng cách sử dụng' B'. – sepp2k

+0

Tôi hiểu rồi. Cảm ơn! Tôi nghĩ tuple là cần thiết để phù hợp với 'A (x, y)'. – Stas

0

Chúng là hai loại khác nhau. Việc giải thích cú pháp này là mơ hồ tại nhà điều hành *. Nó có thể giảm xuống thành dạng:

type x = Y * Z trong đó '*' được kết hợp với từ khóa type trong OCaml hoặc int * int trong đó * được sử dụng với tư cách một nhà điều hành mà xây dựng một tuple

Ưu tiên mặc định sẽ chuyển nó về trước. Bằng cách đặt dấu ngoặc đơn xung quanh (int * int), bạn ghi đè quyền ưu tiên mặc định và bắt buộc diễn giải sau.

2

Như đã nói, hàm tạo của A mất hai int, trong khi hàm tạo của B có cặp được đặt hàng.

vì vậy bạn có thể viết

let bar = A (1, 2) 

hoặc

let bar = B (1, 2) 

hoặc

let bar = (1, 2) 
let baz = B bar 

nhưng bạn không thể viết

let bar = (1, 2) 
let baz = A bar 

Hơn nữa, trong mô hình kết hợp của bạn, bạn vẫn có thể phù hợp với nội dung của B là hai int, nhưng bạn không thể phù hợp với nội dung của A là giá trị ràng buộc vào một cặp lệnh

let test_foo = function 
    | A a -> a (* wrong *) 
    | B (f, s) -> (f, s) (* ok *) 
0

Đây là một trong những điều khó khăn trong Cú pháp OCaml - mặc dù có vẻ như bạn đang khai báo một hàm tạo với kiểu dữ liệu tuple (A of int * int), và mặc dù khi bạn sử dụng hàm tạo, có vẻ như bạn đang đưa ra một bộ dữ liệu cho nó (A (2,3)), đó không phải là những gì đang xảy ra.

Nếu bạn thực sự xây dựng một giá trị tuple và cố gắng chuyển nó tới hàm tạo, nó sẽ không biên dịch - let x = (2,3) in A x. Thay vào đó, * trong định nghĩa hàm tạo và (,) trong biểu thức sử dụng hàm tạo chỉ đơn giản là cú pháp cho hàm tạo của nhiều đối số. Cú pháp bắt chước của một hàm tạo với một đối số tuple, nhưng thực sự tách biệt. Các dấu ngoặc đơn phụ là cần thiết nếu bạn muốn thực sự tạo một hàm tạo với một đối số tuple đơn.