The trick is to have a small set of functions which are very generic. And then stack these on top of each other as a mini-language from which you build up the access pattern you desire. After all it is a functional language, so these kinds of constructions should be fairly simple.
As for representation, consider that a book is represented as a tree: chapter -> section -> subsection -> paragraph -> body_text. But nobody said that this was the natural representation in a machine. You could have made a database table - CREATE TABLE book (id SERIAL, chapter INT, section INT, ..., body_text TEXT). Now access is by a small mini-language, namely SQL SELECT statements. Another way is to represent Chapter, Subsection, ... as dimensions in a vector space. The body text is then a point at a coordinate of Chapter x Section x Subsection. This has a KD-tree representation because it has neat spatiality for instance.
We could represent the book as a list: [(chapter section subsection ... body_text) ...]. A list has a formal derivative called a "zipper". This structure allows us to go "forward and back" through the paragraphs of the book - one paragraph at a time. This is the perfect representation for a screen reader. If we need to go larger strides, we can probably consider a zipper of a Rope-structure or a finger tree.
Finally, we could use a trick where the book is represented as a function. That is, we simply call book(3, 12, 32, 4) to get Chapter 3, Section 12, Subsection 32 paragraph 4.
What I really don't like about OO is when it is taken as the assumption that physical objects in our world has an isomorphic representation in the machine. This is nearly never the case. Good OO programmers naturally know when to break away from an isomorphic representation - but sadly this is not always what is taught in schools. You know, a Cat is an animal and so is a dog. Hence they are both subclasses of the animal class :)