Решение в ответах Томаса и Каго является функционально правильным. Одна проблема, которая может беспокоить вас, если вы используете их решение «как есть», состоит в том, что вы получите больше коллизий, чем ожидалось, если у вас будет хэшировать много ключей, которые равны для (=)
и отличаются для (==)
. Действительно, все ключи, равные для (=)
, имеют одинаковый хеш для Hashtbl.hash
и в конечном итоге оказываются в одном и том же сегменте, где они распознаются как разные (поскольку вы просили использовать (==)
в качестве функции равенства) и создавать разные привязки. В худшем случае хеш-таблица будет работать с той же сложностью, что и список ассоциаций (что, кстати, является еще одной структурой данных, которую вы можете использовать, и тогда вам не придется беспокоиться о предоставлении хеш-функции). ).
Если вы можете принять ключ значения, изменяющегося время от времени (и, следовательно, значение, которое невозможно получить из хеш-таблицы, поскольку в этом случае привязка находится в неправильном сегменте), вы можете использовать следующую низкоуровневую функцию как хэш:
external address_of_value: 'a -> int = "address_of_value"
Реализовано в C как:
#include "caml/mlvalues.h"
value address_of_value(value v)
{
return (Val_long(((unsigned long)v)/sizeof(long)));
}
Затем вы бы использовали:
module H = Hashtbl.Make(struct
type t = foo
let equal = (==)
let hash = address_of_value
end);;