Assume I have a record with a Hashtbl field:
type rec = {
table : (int, int) Hashtbl.t;
value : int;
(* more fields... *)
}
How should I update it in a functional way, i.e. something like that:
let new_rec = { old_rec with
value = old_rec.value + 1 ; (* that's ok *)
table = hash_table + (key -> value binding) (* but how should I do this??? *)
}
I’d love to hear about general approach, that’s not specific to Hashtbl. I’ll obviously have to copy such a structure, and then modify the copy. But what I’m experiencing difficulty with is how to make the resultant code as “functional” as possible.
The general problem you are trying to solve is to take a mutable data structure and treat it as if it were immutable. The fact that this occurs as you create a new record is a red herring here. (Although I will point out that because you are creating a record in which every field is different, the
old_rec withis superfluous and distracting.)The general solution to treating a mutable data structure as if it were immutable is copy, then mutate. But this solution is fraught with peril:
It’s not clear under exactly what circumstances a shallow copy is good enough or when you might have to write a deep copy.
If the abstraction is mutable, there’s no guarantee it even offers a copy operation (or the appropriate copy operation).
Copies can be expensive, especially deep copies.
This considerations are what lead people to avoid mutable state in the first place. I realize that this is hard to do in Caml, because the standard libraries are unusually imperative for a functional language. Nevertheless, I believe the correct “general” strategy in the long run is to replace mutable abstractions with purely functional data structures.
Addendum: Here’s a example for hash tables:
Provided
Hashtbl.copyis deep enough, you can use this as a functional way of extending a hash table. But you’d be better off with red-black trees.