dan
dan

Reputation: 1002

Clojure function evaluation

I was searching for a Clojure logarithm function and concluded there really isn't one for v1.3+. What took me so long to invoke Math/log was this:

user=> Math/log

CompilerException java.lang.RuntimeException: Unable to find static field: log in class java.lang.Math, compiling:(NO_SOURCE_PATH:0:0)

I tried variations like (use 'java.lang.Math) and so forth. It wasn't until I tried an example that I found it's there after all:

user=> (Math/log 10)
2.302585092994046

This must be by design, but what is the reason?

Upvotes: 4

Views: 1884

Answers (3)

Thumbnail
Thumbnail

Reputation: 13473

A static method imported from Java is not a Clojure function or any other kind of Clojure object. The compiler reports any misfit as a missing field, even where the context is looking for a function. All of these ...

Math/log
(Math/log)
(map Math/log (range 1 5))

... produce such errors.

For a corresponding Clojure function:

  • inc returns the function;
  • (inc) reports ... wrong number of args(0) ...;
  • (map inc (range 1 5)) returns (2 3 4 5).

You can wrap a Java method as a Clojure one:

(defn log [x] (Math/log x))

... getting the expected result:

(map log (range 1 5))
;(0.0 0.6931471805599453 1.0986122886681098 1.3862943611198906)

The Clojure Java Interop page recommends

(map #(Math/log %) (range 1 5))

... in such cases.

Upvotes: 6

ntalbs
ntalbs

Reputation: 29448

Clojure provides some forms for interoperating with Java classes, methods, and fields. When you access static field in a class, you can do it like this:

user=> Integer/MAX_VALUE
;=> 2147483647
user=> Math/PI
;=> 3.141592653589793

And when you want to invoke static method, you can use the following form

user=> (Math/log 10)
;=> 2.302585092994046
user=> (Math/sin 1)
;=> 0.8414709848078965

When you try to evaluate just Math/log, clojure think it's static field, which is not true.

user=> Math/log

;=> CompilerException java.lang.RuntimeException: Unable to find static field: log in class java.lang.Math, compiling:(/private/var/folders/jh/q738l9dn0hxg0vvwbty7m5hw0000gp/T/form-init145007798854806400.clj:1:5845)

You can see it from the error message(Unable to find static field:...) that the clojure REPL try to find static field log from Math class, then failed.

Upvotes: 4

Alan Thompson
Alan Thompson

Reputation: 29958

In Java, one uses parentheses to invoke a function:

println("hi");

Clojure also uses parentheses to invoke a function, but with a different placement:

(println "hi")

In either Java or Clojure, just typing:

println

is an error, because you don't have the parentheses to indicate a function call.

In your first example, you use the name of the function Math/log, but you had no parentheses to tell the REPL that you wanted to invoke a function.

Also, in Java, parentheses can indicate either a function call or a grouping operator:

println(2 + (3 + 4))

In Clojure, parentheses only indicate function calls, and never indicating simple grouping.

Upvotes: 1

Related Questions