Based on the answer by @Ingo,
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.
and comments thereto as well as the solution for PersistentMap by Adam Bard, I came up with a working solution:
module foo.Foo where
[EDIT] As Ingo points out, being an instance of ListView gives us list comprehension, head, tail, …
instance ListView PersistentVector
We need to annotate a Clojure class for use in Frege (pure native basically makes the Java methods available to Frege without needing any monad to handle mutability, possible because—in general—data is immutable in Clojure, too):
data PersistentVector a = native clojure.lang.IPersistentVector where
-- methods needed to create new instances
pure native empty clojure.lang.PersistentVector.EMPTY :: PersistentVector a
pure native cons :: PersistentVector a -> a -> PersistentVector a
-- methods needed to transform instance into Frege list
pure native valAt :: PersistentVector a -> Int -> a
pure native length :: PersistentVector a -> Int
Now there follow some functions that are added to this data type for creating a Clojure vector from Frege list or the other way around:
fromList :: [a] -> PersistentVector a
fromList = fold cons empty
toList :: PersistentVector a -> [a]
toList pv = map pv.valAt [0..(pv.length - 1)]
Note my use of the "dot" notation; see the excellent article by @Dierk, The power of the dot.
[EDIT] For ListView (and some fun in Frege with PersistentVector) we need to also implement uncons, null and take (sorry for the quick & dirty solutions here; I will try to fix that soon):
null :: PersistentVector a -> Bool
null x = x.length == 0
uncons :: PersistentVector a -> Maybe (a, PersistentVector a)
uncons x
| null x = Nothing
-- quick & dirty (using fromList, toList); try to use first and rest from Clojure here
| otherwise = Just (x.valAt 0, fromList $ drop 1 $ toList x)
take :: Int -> PersistentVector a -> PersistentVector a
-- quick and dirty (using fromList, toList); improve this
take n = fromList • PreludeList.take n • toList
In my quick & dirty solution above, note the use of PreludeList.take to avoid calling take in the namespace that PersistentVector creates, and how I did not have to prefix fromList, toList, cons and empty.
With this setup (you can leave out uncons, null and take as well as the instance declaration at the top, if you don’t want to do anything with PersistentVector in Frege directly) you can now call a Frege function that takes and returns a list by wrapping it properly:
fromClojure :: PersistentVector a -> PersistentVector a
fromClojure = PersistentVector.fromList • myfregefn • PersistentVector.toList
-- sample (your function here)
myfregefn :: [a] -> [a]
myfregefn = tail
In Clojure we just call (foo.Foo/fromClojure [1 2 3 4]) and get a Clojure vector back with whatever processing myfregefn does (in this example [2 3 4]). If myfregefn returns something that both Clojure and Frege understand (String, Long, …), leave out the PersistentVector.fromList (and fix the type signature). Try both out, tail as above for getting back a list and head for getting back, say, a Long or a String.
For the wrapper and for your Frege function, make sure the type signatures 'match', e. g. PersistentVector a matches [a].
Moving forward: I am doing this because I would like to port some of my Clojure programs to Frege, “a function at a time“. I am sure I will be encountering some more complex data structures that I will have to look into, and, I am still looking into the suggestions by Ingo to improve things.