Question regarding example in Stuart Halloway's book (page 120)

5 views
Skip to first unread message

arasoft

unread,
Jun 24, 2009, 7:02:52 PM6/24/09
to Clojure
Why does this work?

(take-while (complement #{\a\e\i\o\u}) "the-quick-brown-fox")

When I do something similar, like

(take-while (complement #(Character/isWhitespace %)) "the-quick-brown-
fox")

I have to deal with the parameter explicitly ("%"). How is the
parameter hidden in the set/function? Could I do something like that
in my own code (not sure I'd want to, just curious what magic is at
work here)?

Richard Newman

unread,
Jun 24, 2009, 7:17:25 PM6/24/09
to clo...@googlegroups.com
> Why does this work?
>
> (take-while (complement #{\a\e\i\o\u}) "the-quick-brown-fox")
>
> When I do something similar, like
>
> (take-while (complement #(Character/isWhitespace %)) "the-quick-brown-
> fox")
>
> I have to deal with the parameter explicitly ("%"). How is the
> parameter hidden in the set/function?

The set *is* a function (it implements IFn). complement accepts a
function as input, so that works.

Character/isWhitespace is a Java static method, which is not a first-
class function, and thus can't be passed directly to complement.

The #(...) syntax is shorthand for (fn [...] ...), which introduces a
new anonymous function. What you've written there is equivalent to

(defn whitespace? [c]
(Character/isWhitespace c))

(take-while (complement whitespace?) "the quick")


... i.e., you've made a function that calls a Java static method on
its input.


> Could I do something like that
> in my own code (not sure I'd want to, just curious what magic is at
> work here)?

In your Java code, implement IFn. That's the magic. In your Clojure
code, just hand around functions.

Stephen C. Gilardi

unread,
Jun 24, 2009, 7:18:53 PM6/24/09
to clo...@googlegroups.com

In addition to functions, several of Clojure's other objects are
"invokable"--they can operate successfully as the first item in a call
expression (a list in code).

Invoking a set returns the element in the set that's = to the argument
or nil
Invoking a map returns the value in the map whose corresponding key is
= to the argument or nil
Invoking a keyword requires a map as its argument and returns the
value in the map corresponding to the key that's = to the keyword or nil

"Being invokable" in Clojure is equivalent to implementing the IFn
interface. You can see in this diagram which objects in Clojure
implement IFn:

http://github.com/Chouser/clojure-classes/blob/032beae497fddc426db05c7c6367c625a2dad04f/graph-w-legend.png

(IFn is at the lower right).

The core function "ifn?" can also let you know if something is
invokable:

Clojure 1.1.0-alpha-SNAPSHOT
user=> (ifn? #{:a :b :c})
true
user=> (ifn? 3)
false
user=> (fn? #{:a :b :c})
false
user=>

--Steve

arasoft

unread,
Jun 24, 2009, 7:23:20 PM6/24/09
to Clojure
Thank you for a comprehensive explanation!!!

Rich Hickey

unread,
Jun 24, 2009, 8:52:38 PM6/24/09
to clo...@googlegroups.com

For all those who want to understand how the class hierarchies map to
various Clojure abstractions, I have broken down that (rather
daunting) graph into separate areas in various slides from the
tutorial I gave at ILC09:

http://clojure.googlegroups.com/web/tutorial.pdf

There you can much more clearly see how the collections, seqs, refs,
and various concepts like
sequential/associative/counted/reversible/metadata/callability/java
collection/java interop are organized.

Rich

Rowdy Rednose

unread,
Jun 26, 2009, 7:03:56 AM6/26/09
to Clojure
I find the pdf actually pretty useful as a quick reference until I'm
familiar with all the function names.

There's however a small mistake on page 28. The 'd' doesn't belong
there in the 2nd line of this example:

(let [{a :a, b :b, c :c, :as m :or {a 2 b 3}} {:a 5 :c 6}]
[a b c d m])
-> [5 3 6 {:c 6, :a 5}]

Rowdy

On Jun 25, 9:52 am, Rich Hickey <richhic...@gmail.com> wrote:
> On Wed, Jun 24, 2009 at 7:18 PM, Stephen C. Gilardi<squee...@mac.com> wrote:
>
> > On Jun 24, 2009, at 7:02 PM, arasoft wrote:
>
> >> Why does this work?
>
> >> (take-while (complement #{\a\e\i\o\u}) "the-quick-brown-fox")
>
> >> When I do something similar, like
>
> >> (take-while (complement #(Character/isWhitespace %)) "the-quick-brown-
> >> fox")
>
> >> I have to deal with the parameter explicitly ("%"). How is the
> >> parameter hidden in the set/function? Could I do something like that
> >> in my own code (not sure I'd want to, just curious what magic is at
> >> work here)?
>
> > In addition to functions, several of Clojure's other objects are
> > "invokable"--they can operate successfully as the first item in a call
> > expression (a list in code).
>
> > Invoking a set returns the element in the set that's = to the argument or
> > nil
> > Invoking a map returns the value in the map whose corresponding key is = to
> > the argument or nil
> > Invoking a keyword requires a map as its argument and returns the value in
> > the map corresponding to the key that's = to the keyword or nil
>
> > "Being invokable" in Clojure is equivalent to implementing the IFn
> > interface. You can see in this diagram which objects in Clojure implement
> > IFn:
>
> >http://github.com/Chouser/clojure-classes/blob/032beae497fddc426db05c...
Reply all
Reply to author
Forward
0 new messages