The suspended goal would typically be a demon (because it is going to be woken repeatedly, on every change). hash_insert_suspension/3 also supplies a Notifications argument, which should be used as one of the arguments of the suspended goal (see example). This is a "receive port" as defined by library(notify_ports), and is used to convey information about the changes that happened to the hash table. The notifications are of the following form:
    % Program:
	hash_create_verbose(H) :-
	    hash_create(H),
	    make_suspension(report(Notifications,Susp), 2, Susp),
	    hash_insert_suspension(H, Susp, Notifications).
	:- demon(report/2).
	report(Notifications, Susp) :-
	    notify_ports:receive_notifications(Notifications, List, Status),
	    writeln(changes:List),
	    ( Status = closed -> kill_suspension(Susp) ; true ).
    % Sample execution
    ?- hash_create_verbose(H),
       hash_set(H,k1,v1), hash_set(H,k1,v2), hash_delete(H,k1),
       hash_terminate_suspensions(H).
    changes : [add(k1, v1)]
    changes : [chg(k1, v1, v2)]
    changes : [rem(k1, v2)]
    changes : []
    H = hash(4, 0, [])
    Yes (0.00s cpu)