La soluzione nelle risposte di Thomas e Cago è funzionalmente corretta. Un problema che potrebbe causare problemi se si utilizza la propria soluzione così com'è è che si otterranno più collisioni del previsto se si hanno molte chiavi uguali per (=)
e diverse per (==)
. Infatti, tutte le chiavi uguali per (=)
hanno lo stesso hash per Hashtbl.hash
e finiscono nello stesso bucket, dove sono riconosciute come diverse (dal momento che hai chiesto di utilizzare (==)
come funzione di uguaglianza) e creare associazioni diverse. Nei casi peggiori, la tabella hash si comporterà con la stessa complessità di una lista di associazioni (che, a proposito, è un'altra struttura dati che potresti usare, e quindi non dovresti preoccuparti di fornire una funzione hash).
Se è possibile accettare la chiave di un valore che cambia occasionalmente (e quindi il valore è impossibile da recuperare dalla tabella hash, poiché l'associazione è quindi nel bucket errato), è possibile utilizzare la seguente funzione di basso livello come hash:
external address_of_value: 'a -> int = "address_of_value"
Implementato in C come:
#include "caml/mlvalues.h"
value address_of_value(value v)
{
return (Val_long(((unsigned long)v)/sizeof(long)));
}
Si potrebbe quindi utilizzare:
module H = Hashtbl.Make(struct
type t = foo
let equal = (==)
let hash = address_of_value
end);;
fonte
2012-01-23 16:22:34
Questo tipo di confronto di hash è un po 'fragile se utilizzato con valori immutabili, come nel tuo esempio. I documenti dicono che il risultato di (==) dipende dall'implementazione in quel caso: vedi il modulo [Pervasives sotto ** Comparisons **] (http://caml.inria.fr/pub/docs/manual-ocaml/libref/ Pervasives.html). In teoria, il compilatore o il runtime possono far sì che due valori uguali immutabili siano fisicamente uguali, se lo desiderano. –
@JeffreyScofield Il compilatore o il runtime possono anche causare valori che ci si aspetterebbe essere fisicamente uguali a diversi, e ciò non è teorico: 'lascia test x = let t = Array.make 1 x in x == t. (0) ;; test 1.0 ;; 'compute' false'. Il GC multi-thread per Caml che esiste solo sulla carta può anche duplicare valori immutabili. –
Grazie, sono esempi molto interessanti, anche se penso che l'OP sia più interessata all'altra faccia della medaglia. Non puoi dipendere da valori immutabili con identità fisiche uniche (a! = B) a meno che non siano uguali (a <> b). La solita soluzione (o, quella che ho usato) è mantenere un identificatore univoco nei valori. Questo aiuta anche con l'hashing, ovviamente. –