How to get an Fn which calls a Java method?

后端 未结 4 1307
梦谈多话
梦谈多话 2021-01-20 22:33

I\'m learning Clojure. I wrote this code to recursively walk a directory.

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

相关标签:
4条回答
  • 2021-01-20 23:07

    Java methods aren't clojure functions because you can't call a method on its own; you have to call a method on an object, and it has to be an object of the type that the method expects. In other words, in java, a method cannot be fully separated from its defining class (at least not efficiently).

    An alternative to #(.foo %) would be (memfn foo), which hardly anyone uses anymore after #(...) was introduced.

    0 讨论(0)
  • 2021-01-20 23:12

    You could have a look at the sourcecode of file-seq (which uses a tree-seq) to see how it works.

    By the way: your code works perfectly well for me. I just have to use java.io.File instead of File in the REPL so it knows the Java class.

    0 讨论(0)
  • 2021-01-20 23:25

    Joost is spot on about Java methods not being first class functions.

    As an approach to dealing with this, I usually like to wrap Java functions in a Clojure function (or find a library that does this already), then it is easy to use them in an idiomatic first-class way:

    (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"))
    

    This is a few more lines of code, but has the following advantages:

    • You can add type hints in your functions to avoid reflection (as above)
    • The final code is cleaner and more idiomatic
    • You have abstracted away from the underlying Java interop
    0 讨论(0)
  • 2021-01-20 23:29

    You've already been given the correct answers, but just to add a bit more Clojure idiomatic code, I'd also use

    #(.foo %)
    

    as Joost Diepenmaat did (yet I believed it might've been overlooked).

    I would also suggest reading Listing files in a directory in Clojure.

    0 讨论(0)
提交回复
热议问题