Generalize to allow different data models, add JSON

It can be useful to fingerprint based on other kinds of equivalency
besides clojure-runtime equivalency, for example equivalency in a JSON
serialization. I refactored a bit to allow a `canonizer` function to
be supplied, and added a fingerprint-json function.