6

I have a data structure in Clojure which represents a set of results from an experiment:

(defprotocol ResultSet
  (columns [rs] "return a collection of the columns in the resultset, represented by keywords")
  (rows [rs] [rs column-keys] "returns a seq of the rows in the resultset, order and column specified as keywords by column-keys. with a single argument returns rows with all columns present"))

And I have a deftype which implements this protocol. I am interested in writing functions which do things like map a function over all the results in the resultset, or which fold over the result set, basically doing the same things as the built in seq functions.

In Haskell I would do this by implementing the relevant typeclasses (eg Functor) and then using functions like fmap or mfilter. So I looked into doing this in Clojure and wound up with some ideas about implementing the ISeq interface.

So, is this a good idea? I can't find many resources about implementing ISeq and I am wondering what the idiomatic approach to this is.

Alex jg
  • 915
  • 11
  • 23

2 Answers2

5

As far as I can tell, the "best" way to implement something like this is not to implement ISeq, but clojure.lang.Seqable; in other words, provide an implementation of (.seq) to map your ResultSet to a (possibly lazy) sequence. That is the route clojure uses for most (all?) collections except list (lists implement ISeq, because the seq API is already a subset of the list API).

Joost Diepenmaat
  • 17,633
  • 3
  • 44
  • 53
  • This will allow me to do something like return the underlying sequence of rows in a resultset, but it doesn't allow me to map a function over a `Results` and get back a `Results` does it? EDIT: I've just realised that the built in map doesn't behave like this, maybe I'm trying to do the wrong thing. – Alex jg Sep 06 '11 at 09:56
  • 1
    As you say in your edit, the clojure sequence functions generally call (seq) on the provided collection and then work on and return seqs, not any specific type of collection. It seems a bit unintuitive at first, but in practice it works really well. All you really need is some way of turning a seq back into the collection type you need, when you really need it (which isn't all that often, once you're working on seqs - it might be worth considering whether you even need a ResultSet type at all) – Joost Diepenmaat Sep 06 '11 at 10:25
0

I think I'm misunderstanding your question but wouldn't you just use map to apply a function to each element in your result.