On Wed, Apr 28, 2010 at 2:54 PM, Stuart Halloway
<
stuart....@gmail.com> wrote:
> Intentional, see map-indexed and keep-indexed.
>
> Stu
Hmmm, I can see the appeal of a "give them the general so they can
make the specific" philosophy, but there's also something to be said
for "give them easy-to-understand building blocks so they can build
what they need". In this case, it seems to be about the same
complexity to derive the general from the specific (combining building
blocks), as to derive the specific from the general.
Unless I'm misunderstanding these new functions, it seems like if you
have indexed, then these functions, as well as many others, can be
easily expressed with Clojure's other building blocks, for example:
(map-indexed f coll) <=> (for [[index element] (indexed coll)] (f
index element))
Many times, you're writing f as an anonymous function anyway, and can
just as easily make it work on pairs, in which case
(map-indexed f coll) can just be written as (map f-written-for-pairs
(indexed coll))
Just one man's opinion, but I definitely prefer indexed as the
building block, and the others as the derived forms, rather than vice
versa. I find that I just as frequently want to use indexed sequences
in doseq just as much as in for, and sometimes with functions that
work as pairs as well as ones that work on the index and elements
individually. I can express all these permutations fairly easily with
indexed. On the other hand, if map-indexed is the primitive, then you
end up writing something like this to print an indexed sequence s,
which feels convoluted to me:
(doseq [[index element] (map-indexed vector s)] (printf "%d - %d\n"
index element))
As an analogy, I think it's interesting to contrast Clojure's range
over Scheme's build-list.
Scheme provides a general list-building function that's analogous to
mapping over a range.
(build-list n f) in Scheme is equivalent to Clojure's (map f (range n))
In Scheme, range is not built-in. Despite the fact that it is the
common case, you end up constantly writing things like (build-list n
(lambda (i) i)) to express (range n). It gets annoying fast, and
newcomers to the language complain about needing to use higher-order
functions just to express something as simple as a range.
I think Clojure made the right call by including range rather than
build-list in the core. It's the common case, and you can easily do
(map f (range n)) when you want to apply a function to everything in
the range. You have a great building block to work with.
I feel that map-indexed is almost exactly analogous to Scheme's
build-list, and indexed is analogous to range. Looking at it in that
way, including indexed feels far more Clojurian to me than the current
plan to use map-indexed.
I think I see the utility of keep, although in my own code, I find
that just as frequently I want to strip out false values, or nil
values, or both. I can express all these easily enough with filter:
(filter (complement false?) coll)
(filter (complement nil?) coll)
(filter identity coll)
It's not really clear to me why stripping out nil is so much more
useful than the other variations that people want it in the core, so
I'd be curious to know what the reasoning was.