First, a disclaimer: I'm not deeply familiar with the uniform access principal so you may want to take this with a grain of salt. That said, I would argue that Clojure does observe a uniform access principle: function calls.
The key quote on Wikipedia seems to be "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation", and that's exactly the case with function calls in Clojure. The function's name may indicate that it has side effects (by ending in an exclamation mark) but otherwise they behave the same. Function call notation is extremely widespread in Clojure, from "normal" functions, to
hash-map access by key,
vector access by index,
set membership testing, etc. And you can implement function call behavior for your own types by implementing
(deftype Invokable  clojure.lang.IFn (invoke [this] :was-invoked)) (def invokable (Invokable.)) (invokable) ;=> :was-invoked
You may have in mind the use of keywords as functions, which are most specifically associated with hash-maps, but you can actually implement that behavior for different types as well. Here's a silly example because I couldn't come up with anything better that involved IO and wasn't too long:
(deftype WeirdKlass  clojure.lang.ILookup (valAt [this k not-found] (let [home (System/getProperty "user.home") file (io/file home (name k))] (if (.isFile file) (slurp file) not-found))) (valAt [this k] (.valAt this k nil))) (def klass (WeirdKlass.)) ;; assuming you have a file at $HOME/testfile (:testfile klass) ;=> "test content!" (:blah klass) ;=> nil (:blah klass :not-found) ;=> :not-found