lambda function returning a constant?

520 views
Skip to first unread message

julianrz

unread,
Sep 4, 2011, 4:56:17 PM9/4/11
to Clojure
Hello All,
I am new to Clojure. Surprised why this code does not work:

user=> (filter #(%) [1 2 3])
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn

Here my intent behind #(%) is to define a lambda function returning
its argument. Since Clojure defines truth on any type, it should be
acceptable as filter function, and the result should be the original
array

Some narrowing down. What's #(%) really good for?

user=> #(%)
#<user$eval48$fn__49 user$eval48$fn__49@5e2c17f7>

so it is a function

user=> (#(%))
ArityException Wrong number of args (0) passed to: user$eval26$fn

Ok, here not enough arguments supplied, fair enough. Let's fix that:
user=> (#(%) 1)
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn

Same problem as the first example. So Clojure understands this is a
function, knows it takes some arguments, but cannot call it? What's
wrong? The following works:

(user=> (filter (fn [a] a) [1 2 3])
(1 2 3)

So apparently it has something to do with the fact that #() is
shorthand. So in my case, it produces a function which cannot be
used... In fact, it seems to just yield the constant, not a function.
Ask me, it should work (auto-wrap the constant in a function) or the
expression should be illegal. I think it deserves better
diagnostics...

Also, in Practical Clojure book, it says: "The shothand function form
#(* %1 %2) is actually identical to the longer form (fn [x y] (* x y))
before it is even seen by the compiler." If you literally apply this
rule, you will get

((fn[x] (1)) 1)

which throws same exception, not surprisingly, since it tries to
evaluate 1 as a fucntion. What it should have done is transform the
expression into

((fn[x] 1) 1)

which works fine... Special-case it?

What do you think?

Julian

Laurent PETIT

unread,
Sep 6, 2011, 3:44:30 PM9/6/11
to clo...@googlegroups.com


2011/9/4 julianrz <juli...@yahoo.com>

Hello All,
I am new to Clojure. Surprised why this code does not work:

user=> (filter #(%) [1 2 3])
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn

Here my intent behind #(%) is to define a lambda function returning
its argument. Since Clojure defines truth on any type, it should be
acceptable as filter function, and the result should be the original
array

Some narrowing down. What's #(%) really good for?

Hello,

#(%) is a macro which expands to (fn* [p1#] (p1#))

#(%) could only be 'useful' if % is a callable without arguments.

What you seem to be after is the builtin function named identity : identity returns its argument :

Clojure> (filter ident­ity [1 true false­ nil])­
(1 true)
Clojure> 

HTH,

--
Laurent

 
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Alan Malloy

unread,
Sep 6, 2011, 5:02:32 PM9/6/11
to Clojure
As Laurent says, you should just use the built-in `identity` function,
but you can write it yourself: as you noticed, (fn [x] x) works, but
if you want to do it with the shorthand syntax you can use #(do %).

julianrz

unread,
Sep 6, 2011, 10:32:14 PM9/6/11
to Clojure
Thanks, I realize my example is a bit of a corner case, and feels a
little artificial:) It came after some narrowing down a larger problem

Another thing that appeared curious to me, is that Clojure apparently
counts unique %'s inside the #() definition to determine arity of the
macro. But does this mean that macros with no arguments should be
legal?
How about this:

(#(true)), is this not calling a function that has no arguments and
returns true? But it still gives same exception

<CompilerException java.lang.ClassCastException: java.lang.Boolean
cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)>

I come from Scala experience, where it is easy to define a quick
lambda function returning a constant or another simple expression,
e.g. "=> true" is a function with no args and returning true. Things
like that are sometimes useful to pass into higher-order functions
expecting a function, not a constant. I guess I should forgo the macro
and go directly with (fn [] true)

I think all of this confusion could have been avoided if the compiler
did a better error message, e.g. actually citing the definition of #()
and what it expanded into? Would improve usability. Even macroexpand
does not provide any useful info in this case...

Certainly macros are not for the fainthearted anyway, but all
literature seems to go into #() really fast, so it will be stumbled
upon by novices

Julian

On Sep 6, 12:44 pm, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> 2011/9/4 julianrz <julia...@yahoo.com>

Armando Blancas

unread,
Sep 6, 2011, 11:43:12 PM9/6/11
to Clojure
> (#(true)), is this not calling a function that has no arguments and
> returns true? But it still gives same exception

Not really:
user=> (macroexpand-1 '#(true))
(fn* [] (true))

> I guess I should forgo the macro
> and go directly with (fn  [] true)

For something like "=> true" try:
user=> (defmacro => [expr] `(fn [] ~expr))
#'user/=> (macroexpand-1 '(=> true))
(clojure.core/fn [] true)

Michael Gardner

unread,
Sep 6, 2011, 11:48:56 PM9/6/11
to clo...@googlegroups.com
On Sep 6, 2011, at 10:43 PM, Armando Blancas wrote:

> For something like "=> true" try:
> user=> (defmacro => [expr] `(fn [] ~expr))
> #'user/=> (macroexpand-1 '(=> true))
> (clojure.core/fn [] true)

Alternatively: (constantly true)

Phil Hagelberg

unread,
Sep 7, 2011, 12:24:09 AM9/7/11
to clo...@googlegroups.com
On Tue, Sep 6, 2011 at 7:32 PM, julianrz <juli...@yahoo.com> wrote:
> I come from Scala experience, where it is easy to define a quick
> lambda function returning a constant or another simple expression,
> e.g. "=> true" is a function with no args and returning true. Things
> like that are sometimes useful to pass into higher-order functions
> expecting a function, not a constant. I guess I should forgo the macro
> and go directly with (fn  [] true)

Have you tried (constantly true)? The main difference is that it will
ignore all arguments, but perhaps it's a more concise way of
expressing what you want.

-Phil

Mark Rathwell

unread,
Sep 7, 2011, 8:24:17 AM9/7/11
to clo...@googlegroups.com
> How about this:
>
> (#(true)), is this not calling a function that has no arguments and
> returns true? But it still gives same exception

This actually is trying to call 'true' as if it were a function, not a
constant. The thing I think you're missing here is: when a symbol is
butted up against an opening parenthesis, it is treated as a function
call, with the remaining elements in the list as arguments (unless the
list is quoted, in which case it is not evaluated and treated as just
a list).

#(true) says call 'true' as a function with no arguments. #(%) says
call the argument passed to this anonymous function as a function, and
if, for example you were mapping a vector of numbers to this anonymous
function, then each number would be called as a function.

As you've already seen, if you just want the original value returned
from a function, you can call the 'identity' function with that
something as an argument, as in #(identity %) or #(identity true),
etc.

Mark Rathwell

unread,
Sep 7, 2011, 9:05:03 AM9/7/11
to clo...@googlegroups.com
> As you've already seen, if you just want the original value returned
> from a function, you can call the 'identity' function with that
> something as an argument, as in #(identity %) or #(identity true),
> etc.

I should have also made clear here that you would never actually use
this in real code, just for learning. See the other responses for the
actual ways to do what you are trying to do.

Reply all
Reply to author
Forward
0 new messages