Clojure函数求值

4
我在寻找Clojure对数函数时发现v1.3+版本中实际上没有这个函数。让我花费了很长时间才调用了Math/log函数,原因是:
user=> Math/log

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

我尝试了各种变体,如(use 'java.lang.Math)等等。直到我尝试了一个例子,才发现它确实存在:

user=> (Math/log 10)
2.302585092994046

这一定是有意为之的设计,但其中的原因是什么呢?

"Math/log" 是一个静态方法。你试图像访问静态变量一样访问它。 - dsm
3个回答

6
从Java导入的静态方法不是Clojure函数或任何其他类型的Clojure对象。即使上下文正在寻找函数,编译器也会将任何不匹配报告为缺少字段。所有这些...
Math/log
(Math/log)
(map Math/log (range 1 5))

...产生这些错误。

对应的Clojure函数:

  • inc返回该函数;
  • (inc)报告...参数数量错误(0)...
  • (map inc (range 1 5))返回(2 3 4 5)

您可以将Java方法封装为Clojure方法:

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

...获得预期结果:

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

在 Clojure Java 互操作 页面中建议使用以下代码:

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

在这种情况下使用。


4

Clojure提供了一些与Java类、方法和字段进行交互的形式。当您访问类中的静态字段时,可以按照以下方式进行:

```clojure (. ClassName fieldName) ```
其中,`ClassName`是Java类名,`fieldName`是静态字段名。
user=> Integer/MAX_VALUE
;=> 2147483647
user=> Math/PI
;=> 3.141592653589793

当您想调用静态方法时,您可以使用以下形式:

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

当您尝试评估Math/log时,Clojure会认为它是静态字段,这并不正确。

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)

你可以从错误信息(Unable to find static field:...) 看出clojure REPL试图从Math类中查找静态字段log,但是失败了。

1
在Java中,使用括号调用函数:
println("hi");

Clojure同样使用括号来调用函数,但是位置不同:
(println "hi")

无论是在Java还是Clojure中,只需键入以下内容:

println

这是一个错误,因为你没有使用括号来表示函数调用。

在你的第一个例子中,你使用了函数 Math/log 的名称,但是你没有括号告诉 REPL 你想调用一个函数。

另外,在 Java 中,括号可以表示函数调用或分组运算符:

println(2 + (3 + 4))

在Clojure中,括号表示函数调用,而从不表示简单的分组。

3
在Clojure中键入println并不会报错,它只是评估为函数本身。 - Diego Basch
3
在Clojure中,函数也是数据(符号),类型为IFn,这就是为什么您不会收到错误信息的原因。然而,Java方法不具有此属性。 - dsm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接