Another way of computing it is Hash.Typed(Hash)(Node).hash t which computes the pre-hash of t before hashing it using Hash. hash_exn might be faster because the it may be optimised (e.g. it may use caching).
hash_exn t is hash_exn ~force:true t which is not expected to raise an exception. hash_exn ~force:false t will raise Not_found if the hash requires IOs to be computed.
cache regulates the caching behaviour regarding the node's internal data which may be lazily loaded from the backend, depending on the node implementation.
cache defaults to true which may greatly reduce the IOs and the runtime but may also increase the memory consumption.
cache = false doesn't replace a call to clear, it only prevents the storing of new data, it doesn't discard the existing one.
Some Node implementations (like irmin-pack's inodes) can represent a node as a set of nodes. One operation on such "high-level" node corresponds to a sequence of recursive calls to the underlying "lower-level" nodes. Note: theses effects are not in the Lwt monad on purpose (so Tree.hash and Tree.equal are not in the Lwt monad as well).
type effect := expected_depth:int ->node_key->t option