Clojure's funcs don't seem to work as expected when sent thru a list

At the Clojure REPL, this expression

( #(for [x %] (+ 100 (second x)))  ['(+ 38) '(+ 48)] )

produces (138 148) as expected

but this

( #(for [x %] ((first x) 100 (second x))) ['(+ 38) '(+ 48)] )

produces (38 48) which seems truly weird.

Both expressions really should be producing the same result! What am I missing? Will appreciate any ideas to resolve this mystery.

BTW, I tried to use 'apply (first x)' and package the rest of the args into a list but it doesn't seem to matter. The same unexpected result comes back.

Also, to verify that the + indeed gets resolved from the input, I gave the following to the REPL

( #(for [x %] (resolve (first x) )) '((+ 38) (+ 48)) )

which produced

 (#'clojure.core/+ #'clojure.core/+)   as expected.

Answers


( #(for [x %] ((first x) 100 (second x))) ['(+ 38) '(+ 48)] )

In this the + is a symbol, not a function, because it has been quoted in the list. However, symbols are defined as doing map lookup when invoked as a function (the same as keywords). So ('+ 100 38) is the same as (get 100 '+ 38). That last argument is the "if you can't find what I want in the map, return that". Since 100 is not a map, + uses that argument as the return value.

To make it do what you want you have two options:

  1. Use vectors instead of quoted lists ensures that + gets resolved appropriately.

    ( #(for [x %] ((first x) 100 (second x))) [[+ 38] [+ 48]] )
    
  2. Resolve it yourself to ensure that you use the + function instead of the + symbol.

    ( #(for [x %] ((resolve (first x)) 100 (second x))) ['(+ 38) '(+ 48)] )
    

When you quote a list, like '(+ 38), none of the items in the list are evaluated. Thus the + is just a symbol and not a reference to the addition function from clojure.core.

The result of calling this symbol as a function is a bit confusing, especially since you happen to call it with exactly two arguments. The reason was already explained by @mange: Invoking a symbol as a function tries to look up the symbol in the first argument, returning the (optional) second argument as a default when the lookup fails:

('x)       ; throws ArityException
('x 1)     ;=> nil
('x 1 2)   ;=> 2
('x 1 2 3) ; throws ArityException

You have several options:

  1. Use vectors instead of quoted lists: [+ 38]. All elements of a vector are evaluated (as in an unquoted list), but the vector is just a data structure, not the syntax for function invocation as is the list.
  2. Use the resolve function to find the function referenced by the symbol. Note that resolve looks up the symbol in the current namespace. So if the construction of the quoted list and the invocation of the function happen in different namespaces, this may lead to surprising results (if you happen to have two different definitions for the same symbol in the different namespaces).
  3. Use syntax quoting instead of simple quoting on the list and unquote the symbol (evaluating it): `(~+ 38)

Need Your Help

Is EndInvoke() optional, sort-of optional, or definitely not optional?

c# multithreading delegates

I've read conflicting opinions as to whether every BeginInvoke() has to be matched by an EndInvoke(). Are there any leaks or other problems associated with NOT calling EndInvoke()?

How to load the current content with jQuery Address plugin on page load?

javascript jquery hash jquery-address

I am not very familiar with the JQuery Address plugin, but i came up with this code, and its working great, except in this situation: When i click on the "nav a", the url is changed and the content...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.