2011-11-27 27 views
7

Bạn có thể mô-trận đấu với nhiều đối số của một hàm bằng cách tạo ra một tuple và sau đó destructuring nó trong một biểu thức phù hợp:Trong OCaml, cách kết hợp kinh điển đối với nhiều đối số của hàm là gì?

let f x y = 
    match x, y with 
    | pattern1 -> expr1 
    | ... 

Ngoài ra, nếu bạn không cần một hàm cà ri, bạn có thể làm điều này bằng cách làm f mất một tuple như là đối số duy nhất:

let f (x, y) = function 
    | pattern1 -> expr1 
    | ... 

Ưu điểm của phương pháp thứ hai là bạn không cần phải viết các đối số hai lần mỗi khi bạn định nghĩa một hàm. Nhưng các chức năng lấy một tuple dường như không phổ biến hơn những người đã khóc.

Vì vậy, cái nào trong hai được coi là kinh điển hoặc được ưa thích trong cộng đồng OCaml?

CHỈNH SỬA: Giống như pad được chỉ ra bên dưới, tôi có nghĩa là let f = function blah blah trong đoạn mã thứ hai.

Trả lời

8

Một bộ dữ liệu không chỉ là một cấu trúc cú pháp, nó đại diện cho một cấu trúc dữ liệu thực sự. Điều này có nghĩa là fun (x,y) là (rất ít) kém hiệu quả hơn f x y trong trường hợp là xy chưa được phân phối, bởi vì một bộ túp phải được phân bổ. Nếu đây là không rõ ràng, tương đương thô trong Java sẽ

void foo(X x, Y y) { ... } 
void bar(Tuple<X,Y> t) { ... } 

/* client code */ 
X x = new X(); 
Y y = new Y(); 

foo(x, y); // Just uses x and y directly 
bar(new Tuple<X,Y>(x, y)); // Has to "new" a Tuple 

Vì lý do này, nó thường thích hợp hơn để tránh sử dụng các bộ như các đối số chức năng, trừ khi bạn có một lý do chính đáng để làm như vậy.

P.S. Một xem xét tương tự áp dụng cho các tờ khai datatype, nơi sau đây là một cách tinh tế khác nhau:

type 'a foo = Foo of 'a * 'a; 
type 'a bar = Bar of ('a * 'a); 

Foo là một constructor datatype mà phải mất hai đối số. Bar là một hàm tạo lấy một đối số (một bộ tuple).

4

Trên thực tế, f = function... là một shortcut của f (x, y) = match (x, y) with... vậy:

let f = function 
    | pattern1_of_x_y -> expr1 
    | ... 

là giống như:

let f (x, y) = 
    match x, y with 
    | pattern1 -> expr1 
    | ... 

(Chú ý rằng có một sai lầm trong công thức thứ hai của bạn, hai phiên bản này không tương thích).

Như bạn đã chỉ ra, người ta không thể tránh sử dụng match ... with... trong một chức năng được thu thập. Cá nhân, tôi thích dạng curried của một hàm vì nó linh hoạt hơn, đặc biệt là với một phần ứng dụng. Hơn nữa, đối sánh mẫu không chỉ được áp dụng trong các đối số hàm; chúng được sử dụng chủ yếu ở mọi nơi trong OCaml, làm cho việc xây dựng match ... with... trở nên quan trọng hơn.

Bất cứ khi nào bạn phát hiện mẫu sử dụng như trên, hãy thử thay thế match ... with... bằng function. Nó chỉ là vấn đề của phong cách, vì vậy không có gì thích hơn ở đây.

8

Giải pháp này là kinh điển:

let f x y = 
    match x, y with 
    | pattern1 -> expr1 
    | ... 

Trình biên dịch tối ưu hóa trường hợp đặc biệt này và không thực sự phân bổ một khối cho tuple (x, y).

3

Cách kinh điển là hàm được kết hợp và match trên bộ dữ liệu, tức là đoạn mã đầu tiên của bạn.

Đây là cách thư viện chuẩn được viết (xem các nguồn thư viện chuẩn, ví dụ: nhiều hàm trong list.ml).

Đây cũng là cách thực hiện được tối ưu hóa cho, đặc biệt là trình biên dịch mã gốc. Nếu bạn tạo một tuple hoặc khối khác và hủy nó ngay lập tức mà không chuyển nó đến các hàm mong đợi một khối, trình biên dịch mã gốc thường phát hiện ra và tránh phân bổ một khối hoàn toàn. Ngay cả khi bạn kết thúc việc phân bổ một khối, nó sẽ hiệu quả hơn để làm cho thời lượng của khối càng ngắn càng tốt, để tăng cơ hội mà khối vẫn ở trong vùng nhớ nhỏ và trong bộ nhớ cache của bộ xử lý.

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