I'm learning Clojure. I wrote this code to recursively walk a directory.
(tree-seq #(.isDirectory %1) #(.listFiles %1) (File. "/my-directory"))
Why can't I use .isDirectory as a first-class function in Clojure? Is there a better way to rewrite this code?
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
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.
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.
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.
Related
I'm trying to advise a number of methods in one library with utility functions from another library, where some of the methods to be advised are defined with (defn) and some are defined with (defprotocol).
Right now I'm using this library, which uses (alter-var-root). I don't care which library I use (or whether I hand-roll my own).
The problem I'm running into right now is that protocol methods sometimes can be advised, and sometimes cannot, depending on factors that are not perfectly clear to me.
If I define a protocol, then define a type and implement that protocol in-line, then advising never seems to work. I am assuming this is because the type extends the JVM interface directly and skips the vars.
If, in a single namespace, I define a protocol, then advise its methods, and then extend the protocol to a type, the advising will not work.
If, in a single namespace, I define a protocol, then extend the protocol to a type, then advise the protocol's methods, the advising will work.
What I would like to do is find a method of advising that works reliably and does not rely on undefined implementation details. Is this possible?
Clojure itself doesn't provide any possibilities to advice functions in a reliable way, even those defined via def/defn. Consider the following example:
(require '[richelieu.core :as advice])
(advice/defadvice add-one [f x] (inc (f x)))
(defn func-1 [x] x)
(def func-2 func-1)
(advice/advise-var #'func-1 add-one)
> (func-1 0)
1
> (func-2 0)
0
After evaluation of the form (def func-2 func-1), var func-2 will contain binding of var func-1 (in other words its value), so advice-var won't affect it.
Eventhough, definitions like func-2 are rare, you may have noticed or used the following:
(defn generic-function [generic-parameter x y z]
...)
(def specific-function-1 (partial generic-function <specific-arg-1>))
(def specific-function-2 (partial generic-function <specific-arg-2>))
...
If you advice generic-function, none of specific functions will work as expected due to peculiarity described above.
If advising is critical for you, as a solution that may work, I'd suppose the following: since Clojure functions are compiled to java classes, you may try to replace java method invoke with other method that had desired behaviour (however, things become more complicated when talking about replacing protocol/interface methods: seems that you'll have to replace needed method in every class that implements particular protocol/interface).
Otherwise, you'll need explicit wrapper for every function that you want to advice. Macros may help to reduce boilerplate in this case.
How can I use java methods as a functions arguments in Clojure?
For example, I want to make a functions composition:
user> (Integer. (str \9))
9
user> ((comp Integer. str) \9)
CompilerException java.lang.ClassNotFoundException: Integer., compiling:(NO_SOURCE_PATH:1:2)
That does not work.
memfn doesn't help also:
user> (map (comp (memfn Integer.) str) "891")
IllegalArgumentException No matching method found: Integer. for class java.lang.String clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)
Any ideas?
Related questions (that, though, do not give the right answer to the question):
Using interop constructor in map function(Clojure)
Why does Clojure say "no matching method" for an illegal argument?
How do I use Clojure memfn with a Java constructor?
How to get an Fn which calls a Java method? (has a nice explanation in the answers)
(Note: it seems to be that the answer suggested by dave, using of an anonymous function as a wrapper, is the best solution)
Unlike Clojure functions, Java methods weren't designed to be first class. When you use Java inter-op in Clojure, you're literally working with Java methods, so you don't get the added benefits that were implemented for Clojure functions. For more info, see the comments below.
As a workaround to use Java methods as arguments, you can wrap them in an anonymous function, like this, effectively making them Clojure functions:
((comp #(Integer. %) str) \9)
How to specify the possibility of two types to a variable?
(defn connect! [(or ^:String :^java.net.InetAddress) host ^:Integer port] ...)
Thanks!
From the Clojure documentation:
Clojure supports the use of type hints to assist the compiler in avoiding reflection in performance-critical areas of code. Normally, one should avoid the use of type hints until there is a known performance bottleneck
The purpose of type hints is to allow the compiler to avoid reflection. Any self-documentation aspects of type-hinted code are secondary. When you say the following:
(defn connect! [^String host])
What you're telling the compiler is to resolve all Java interop method calls on host at compile time to method calls on the String class. Allowing a form to be hinted with multiple classes would defeat this purpose - the compiler wouldn't know which class to compile a method call as. Even if it did, an object cannot be a String and an InetAddress at the same time, so any method calls compiled against the String class would be guaranteed to fail with a ClassCastException if an InetAddress happened to be passed in, and vice versa.
As far as I know the only way is to do the check yourself and add the hint inside a let:
(condp instance? host
String (let [^String s] (...))
InetAddress (let [^InetAddress a] (...)))
Is there a difference, performance or otherwise, between using a deffilterop and using a purse clojure function?
http://nathanmarz.com/blog/introducing-cascalog-a-clojure-based-query-language-for-hado.html mentions that filtering can be done with clojure functions like (< ?age2 ?age1) however looking at https://github.com/nathanmarz/cascalog/wiki/Guide-to-custom-operations it looks like you can define a function like (deffilterop is-2? [x] (= x 2)).
So my question is, is there any difference between these two approaches and if not which is the preferred syntax?
Note: It also looks like all of the defxxxop functions are being deprecated for defxxxfn instead. https://github.com/nathanmarz/cascalog/blob/develop/cascalog-core/src/clj/cascalog/logic/def.clj#L131
Turns out there is no difference from a performance perspective. The deffilterop is useful for making a parameterized function.
I only understood a couple of sections in the reducers talk, one which was that a data-structure could implement the IReducible interface and be able to transform natively, without being turned into a LazySeq first.
I'm hoping to exploit this in clojurescript with native javascript arrays and objects but am not too sure where to start. Can anyone provide an example of how this may be done?
In ClojureScript, the relevant protocol is called IReduce and is already implemented for arrays in the standard library. The relevant extend-type form is here (link to the latest commit on master as of right now).
There's also IKVReduce used by reduce-kv, as well as clojure.core.reducers/reduce in the case of map arguments.
You could provide a wrapper for native objects which you'd like to transform in this way:
(defn wrap-as-reducible [obj]
(reify
IReduce
(-reduce [this f]
...)
(-reduce [this f init]
...)
IKVReduce
(-kv-reduce [this f init]
...)))
Implement either or both of IReduce and IKVReduce according to your needs.
Directly implementing either protocol for "native objects" in general is probably not a good idea, as that would amount to providing a default case which would render checks for reducibility meaningless etc.