3

我正在学习 Clojure。我编写了这段代码来递归地遍历一个目录。

(tree-seq #(.isDirectory %1) #(.listFiles %1) (File. "/my-directory"))

为什么我不能.isDirectory在 Clojure 中用作一等函数?有没有更好的方法来重写这段代码?

4

4 回答 4

7

Joost 指出 Java 方法不是一流的函数。

作为处理这个问题的一种方法,我通常喜欢将 Java 函数包装在 Clojure 函数中(或者找到一个已经这样做的库),然后很容易以惯用的一流方式使用它们:

(defn directory? [^java.io.File file]
  (.isDirectory file))

(defn list-files [^java.io.File file]
  (.listFiles %1))

(tree-seq directory? list-files (File. "/my-directory"))

这是几行代码,但具有以下优点:

  • 您可以在函数中添加类型提示以避免反射(如上)
  • 最终的代码更干净,更惯用
  • 您已经从底层 Java 互操作中抽象出来
于 2012-11-05T11:24:49.610 回答
6

Java 方法不是 clojure 函数,因为您不能单独调用方法;您必须在对象上调用方法,并且它必须是该方法期望的类型的对象。换句话说,在java中,一个方法不能与其定义的类完全分离(至少不是有效的)。

#(.foo %) 的替代方案是 (memfn foo),在引入 #(...) 之后几乎没有人再使用它。

于 2012-11-05T09:58:27.563 回答
1

您可以查看file-seq 的源代码(它使用 tree-seq)来了解它是如何工作的。

顺便说一句:你的代码对我来说效果很好。我只需要在 REPL 中使用 java.io.File 而不是 File,这样它就知道 Java 类。

于 2012-11-05T09:51:25.703 回答
1

你已经得到了正确的答案,但只是为了添加更多的 Clojure 惯用代码,我也会使用

#(.foo %)

正如 Joost Diepenmaat 所做的那样(但我相信它可能被忽视了)。

我还建议阅读Clojure 目录中的列表文件

于 2012-11-05T20:56:59.407 回答