2012-01-23 10 views
6

Có các hashtables trong Ocaml sử dụng == thay vì = khi kiểm tra tính bình đẳng của các khóa không? Ví dụ:Sự bình đẳng trong các thẻ bắt buộc Ocaml

# type foo = A of int;; 
# let a = A(1);; 
# let b = A(1);; 
# a == b;; 
- : bool = false 
# a = b;; 
- : bool = true 
# let h = Hashtbl.create 8;; 
# Hashtbl.add h a 1;; 
# Hashtbl.add h b 2;; 
# Hashtbl.find h a;; 
- : int = 2 
# Hashtbl.find h b;; 
- : int = 2 

Tôi muốn một Hashtable có thể phân biệt giữa ab. Điều đó có thể không?

+0

Loại so sánh băm này hơi mỏng manh khi được sử dụng với các giá trị bất biến, như trong ví dụ của bạn. Các tài liệu cho biết kết quả của (==) phụ thuộc vào việc triển khai thực hiện trong trường hợp đó: xem [Mô-đun Pervasives dưới ** So sánh **] (http://caml.inria.fr/pub/docs/manual-ocaml/libref/ Pervasives.html). Về lý thuyết trình biên dịch hoặc thời gian chạy có thể gây ra bất kỳ hai giá trị bất biến bằng nhau để có thể chất bằng nhau nếu họ muốn. –

+0

@JeffreyScofield Trình biên dịch hoặc thời gian chạy cũng có thể gây ra các giá trị mà bạn mong đợi sẽ khác nhau về mặt vật lý, và đó không phải là lý thuyết: 'let test x = let t = Array.make 1 x in x == t. (0) ;; kiểm tra 1.0 ;; 'tính' sai'. GC đa luồng cho Caml chỉ tồn tại trên giấy cũng có thể nhân đôi giá trị bất biến. –

+0

Cảm ơn, đây là những ví dụ rất thú vị, mặc dù tôi nghĩ OP quan tâm hơn đến phía bên kia của đồng xu. Bạn không thể phụ thuộc vào các giá trị bất biến có các định danh vật lý duy nhất (a! = B) trừ khi chúng không bằng nhau (a <> b). Các giải pháp thông thường (hoặc, một trong những tôi đã sử dụng) là để giữ một định danh duy nhất trong các giá trị của bạn. Điều này cũng giúp với băm, tất nhiên. –

Trả lời

11

Bạn có thể sử dụng hashtables tùy chỉnh:

module H = Hashtbl.Make(struct 
    type t = foo 
    let equal = (==) 
    let hash = Hashtbl.hash 
end) 

Và sau đó sử dụng H thay vì Hashtbl trong mã của bạn.

+0

khi tôi dán mã này vào lỗ hổng của Ocaml, tôi nhận được lỗi cú pháp (dấu ngoặc đơn đóng cuối cùng được gạch dưới). – pbp

+0

thiếu kết thúc 'kết thúc' thành từ khóa' stuct'. – nlucaroni

4

Giải pháp trong câu trả lời của Thomas và cago là chính xác về mặt chức năng. Một vấn đề có thể gây rắc rối cho bạn nếu bạn sử dụng giải pháp của họ như là bạn sẽ nhận được nhiều va chạm hơn dự kiến ​​nếu bạn băm nhiều khóa bằng nhau cho (=) và khác nhau cho (==). Thật vậy, tất cả các khóa bằng nhau cho (=) có cùng giá trị băm cho Hashtbl.hash và kết thúc trong cùng một nhóm, nơi chúng được nhận dạng là khác nhau (vì bạn đã yêu cầu (==) để sử dụng làm hàm bình đẳng) và tạo các ràng buộc khác nhau. Trong trường hợp xấu nhất, bảng băm sẽ hoạt động với độ phức tạp tương tự như danh sách liên kết (mà, bằng cách này, là một cấu trúc dữ liệu khác mà bạn có thể sử dụng, và sau đó bạn sẽ không phải lo lắng về việc cung cấp hàm băm).

Nếu bạn có thể chấp nhận khóa của giá trị thay đổi đôi khi (và do đó giá trị không thể truy xuất từ ​​bảng băm, do ràng buộc trong nhóm không đúng), bạn có thể sử dụng hàm mức thấp sau như băm:

external address_of_value: 'a -> int = "address_of_value" 

thực hiện trong C như:

#include "caml/mlvalues.h" 

value address_of_value(value v) 
{ 
    return (Val_long(((unsigned long)v)/sizeof(long))); 
} 

sau đó bạn sẽ sử dụng:

module H = Hashtbl.Make(struct 
    type t = foo 
    let equal = (==) 
    let hash = address_of_value 
end);; 
+1

Thực tế là các giá trị bằng (=) sẽ băm vào cùng một nhóm là một vấn đề thực sự. Nếu bạn dự định đặt nhiều hơn một vài giá trị bằng nhau (nhưng không thể chất) trong bảng băm của bạn, bạn sẽ thấy hiệu suất rất kém, trừ khi bạn sử dụng hàm băm khác. Xem http: // stackoverflow.com/questions/6757509/stackoverflow-with-specialized-hashtbl-qua-hashtbl-make –

+1

Trong các phiên bản OCaml cũ hơn (tôi không biết nếu nó được thay đổi gần đây), chỉ một GC nhỏ hoặc nén có thể di chuyển một khối, vì vậy băm trên con trỏ đã được an toàn nếu bạn tắt nén và buộc một GC nhỏ trước khi băm. Không phải là tôi muốn đề nghị rằng trong một chương trình bạn muốn duy trì. – Gilles

+0

@Gilles Đó vẫn là trường hợp. Tôi gần như đã chỉ ra thông tin này, nhưng sau đó phản ánh rằng tôi có thể đã được kỹ thuật hơn OP mong muốn. Một số GC đã ghim, nhưng điều đó giống như công cụ sai cho vấn đề này. (==) - hashtables có thể được thực hiện bằng cách giữ các đối tượng nhỏ tách biệt với các đối tượng chính và chỉ phục hồi lại khi cần thiết. Nó vẫn sẽ là cần thiết hoặc để tắt nén hoặc để rehash mỗi khi một trong những xảy ra. –