Passing keys you don't know, comparing strings and not having naming conflicts

1 view
Skip to first unread message

Serge Wroclawski

unread,
Apr 22, 2009, 10:38:23 PM4/22/09
to Clojure Study Group Washington DC
I'm writing some code:

(defn sorted?
"Sees if the sequence passed to it is sorted by key k according to function f"
([comp-fn k coll]
(if (empty? coll)
true)
(sorted? comp-fun k (get (first coll) k) (rest coll)))
([comp-fun k value coll]
(cond
(empty? coll)
true
(fun value (get (first coll) k))
(sorted-by? comp-fn k (get (first coll) k) (rest coll))
:else false)))

This code wants to grow up one day and be wrapped in another function
which will be a component (after I learn the proper use of recur), but
for now I need to understand a few things:

First, it seems the comparison operators in Clojure are less generic
than I hoped. <= and >= are only for numerical operations. That means
no strings and no other objects (like dates). Thoughts on this?
Conditionals? Multimethods? Abandon all hope?

The second problem is I don't know how (or if it's possible) to pass a
key that's not yet defined as such, as in :foo - because that symbol
doesn't yet resolve. I'm not sure about this as an issue either.
Thoughts?

Thirdly, how do other people handle not running into variable names
used by the core?
I've hit that several times today and looking for coping strategies others use.

- Serge

Philip

unread,
Apr 23, 2009, 12:12:54 AM4/23/09
to clojure-...@googlegroups.com
On Wed, Apr 22, 2009 at 22:38, Serge Wroclawski <ema...@gmail.com> wrote:
> First, it seems the comparison operators in Clojure are less generic
> than I hoped. <= and >= are only for numerical operations. That means
> no strings and no other objects (like dates). Thoughts on this?
> Conditionals? Multimethods? Abandon all hope?

There's `compare', http://clojure.org/api#toc150

> The second problem is I don't know how (or if it's possible) to pass a
> key that's not yet defined as such, as in :foo - because that symbol
> doesn't yet resolve. I'm not sure about this as an issue either.
> Thoughts?

Doesn't it just return nil? (get {} :foo) -> nil, (get {} :foo :bar)
-> :bar. {:foo nil} and {} will be equal though, but that probably
makes sense.

I'm refreshing my clojure memory, so I took a stab at different kind
of `sorted?'

(defn sorted-coll?
"Is collection sorted by k according to f?"
([comp-fn k coll]
(every? #(apply comp-fn %) (partition 2 1 (map k coll)))))

Cheers,
Philip

Keith Bennett

unread,
Apr 23, 2009, 4:33:58 AM4/23/09
to clojure-...@googlegroups.com
Guys -

Java has a "Comparable" interface that classes can implement for
ordering. The interface has a "compareTo" method that needs to be
implemented by the class in question. You can find out about it at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html
.

Classes such as Date and String implement Comparable, so you can do:

user=> (.compareTo "a" "b")
-1

Using this, you could write a more friendly interface like:

user=> (defn gt [a b] (> (.compareTo a b) 0))
#'user/gt
user=> (gt "foo" "bar")
true

----

For a Sorted? component, I think Mike was alluding to creating a
generic predicate wrapper component that can be instantiated with any
predicate, right Mike? We could do the same with filters.

----

For a Sorted? component or the like, would we possibly want to make
the flow even finer grained, and have a component called accumulator
or something like that, that would accumulate all the records into a
list, and pass that list to Sorted? as a single record? Then the
bounds of the list would be decided by the accumulator, and that would
be more modular and cohesive. We might want multiple sorted groups in
a single flow, no? Or am I going too far?

----

By the way, the Commons Lang (http://commons.apache.org/lang/api-release/index.html
) and Commons Collections (http://commons.apache.org/collections/api-release/index.html
) libraries could at some point be useful. Commons Lang has a lot of
utilities (String, System, Word, Number, StringEscape). Commons
Collections has collections related utilities and also defines
Closure, Transformer, and Predicate classes that make Java a little
less awful (though we'd probably rarely need to implement these on the
Java side).

- Keith

Serge Wroclawski

unread,
Apr 23, 2009, 6:27:30 AM4/23/09
to clojure-...@googlegroups.com
> (defn sorted-coll?
>  "Is collection sorted by k according to f?"
>  ([comp-fn k coll]
>     (every? #(apply comp-fn %) (partition 2 1 (map k coll)))))

Nice...

- Serge

Serge Wroclawski

unread,
Apr 23, 2009, 7:00:58 AM4/23/09
to clojure-...@googlegroups.com

Comparable seems nice in that it tells you the ordering.

Sadly this function doesn't work with it out of the box because we're
only looking at one thing at a time, and -1 is truthy!

Still I'm extremely impressed by the density of the function.

- Serge

Keith Bennett

unread,
Apr 23, 2009, 1:37:52 PM4/23/09
to Clojure Study Group Washington DC
Ditto...that *is* nice. So the parameter (represented by %) passed to
each call of comp-fn would be the sequence of two values to compare?

BTW, about my previous post, I do agree that using Clojure's compare
would be superior to using Java's Comparable compareTo directly.
That's what I get for posting in my sleep... (not really...). ;)

- Keith

Serge Wroclawski

unread,
Apr 23, 2009, 1:48:10 PM4/23/09
to clojure-...@googlegroups.com
On Thu, Apr 23, 2009 at 1:37 PM, Keith Bennett <keithr...@gmail.com> wrote:
>
> Ditto...that *is* nice.  So the parameter (represented by %) passed to
> each call of comp-fn would be the sequence of two values to compare?

So maybe you can come up with a nice way to wrap compare in the larger
function. The best way I found so far is to look at the first
comparison that's non-zero and then all the subsequent compares must
be that or zero (eg if it's -1, the next one must be either -1 or 0).

The idea would be a function which can return, similarly, a -1 0 or 1,
with 0 being that the function is unsorted- then that gets wrapped in
a function that returns it as:

{:sorted "Unsorted"}

But I can't think of a really nice (read highly clever or efficient)
way to do that.

- Serge

Philip

unread,
Apr 23, 2009, 4:36:38 PM4/23/09
to clojure-...@googlegroups.com
Comparable is ugly though. Fixed set of numbers with special meanings
feels very C, though Python (and some others) also uses similar
comparisons. I think clojure should stick to its generic nature and
express >=, <=, <, > and = in terms of compare (unless type optimized,
etc.)

But you could incorporate compare the following way,

(defn sorted-coll?
"Is collection sorted by k according to f?"
([comparator k coll]
(let [a (map (fapply comparator) (partition 2 1 (map k coll)))]
(or (every? #{-1 0} a)
(every? #{1 0} a))))
([k coll] (sorted-coll? #'compare k coll))
([coll] (sorted-coll? #'identity coll)))

I think it's 2n worst case, but it also keeps an intermediate array of
n ints. Perhaps wrapping stuff in (distinct ...) or even (set ...) and
then testing results might work better.

This can also be used with binary comparison functions like,

(sorted-coll? (comparator #'>) :foo '({:foo 0} {:foo 2} {:foo 6}))

Philip

unread,
Apr 23, 2009, 4:37:21 PM4/23/09
to clojure-...@googlegroups.com
forgot the helper function

(defn fapply [func]
(fn [a & rest]
(apply #'apply func a rest)) )
Reply all
Reply to author
Forward
0 new messages