Inspired by the previous question what is the easiest way to pass a list of integers from java to a frege function? and a comment in the answers by @Ingo, I tried
(Foo/myfregefunction (java.util.List. [1,2,3,4]))
but get (ctor = constructor):
CompilerException java.lang.IllegalArgumentException: No matching ctor found for interface java.util.List
Any ideas? At least java.util.List
didn’t yield a ClassCastException; does this mean this is on the right track?
I can send Frege pretty much any Java collection type from Clojure, see Converting Clojure data structures to Java collections.
BTW, using plain (Foo/myfregefunction [1,2,3,4])
instead yields ClassCastException clojure.lang.PersistentVector cannot be cast to free.runtime.Lazy
, to which @Ingo points out, “A clojure list is not a frege list.” Similar response when casting as java.util.ArrayList
.
On the Frege side, the code is something like
module Foo where
myfregefunction :: [Int] -> Int
-- do something with the list here
Ok, not knowing Clojure, but from the link you gave I take it you need to give the name of an instantiable class (i.e. java.util.ArraList
) since java.util.List
is just an interface and so cannot be constructed.
For the Frege side, which is the consumer in this case, it suffices to assume the interface.
The whole thing gets a bit complicated, since Frege knows that java lists are mutable. This means that there cannot exist a pure function
∀ s a. Mutable s (List a) → [a]
and every attempt to write such a function in a pure language must fail and will be rejected by the compiler.
Instead, what we need is a ST
action to wrap the pure part (in this case, your function myfregefunction
). ST
is the monad that makes it possible to deal with mutable data. This would go like this:
import Java.Util(List, Iterator) -- java types we need
fromClojure !list =
List.iterator list >>= _.toList >>= pure . myfregefunction
From clojure, you can now call something like (forgive me if I get the clojure syntax wrong (edits welcome)):
(frege.prelude.PreludeBase$TST/run (Foo/fromClojure (java.util.ArrayList. [1,2,3,4])))
This interfacing via Java has two disadvantages, IMHO. For one, we introduce mutability, which the Frege compiler doesn't allow us to ignore, so the interface gets more complicated. And in addition, list data will be duplicated. I don't know how Clojure is doing it, but on the Frege side, at least, there is this code that goes over the iterator and collects the data into a Frege list.
So a better way would be to make Frege aware of what a clojure.lang.PersistentVector
is and work directly on the clojure data in Frege. I know of someone who has done it this way with clojure persistent hash maps, so I guess it should be possible to do the same for lists.
(At this point I cannot but point out how valuable it would be to contribute a well thought-out Clojure/Frege interface library!)
Edit: As the self-answer from @0dB suggests, he's about to implement the superior solution mentioned in the previous paragraphs. I encourage everyone to support this noble undertaking with upvotes.
A third way would be to construct the Frege list directly in Clojure.