受之前的问题what is the easiest way to pass a list of integers from java to a frege function?和@Ingo答案中的评论的启发,我尝试了
(Foo/myfregefunction (java.util.List. [1,2,3,4]))
但是获取(ctor =构造函数):
CompilerException java.lang.IllegalArgumentException: No matching ctor found for interface java.util.List
有任何想法吗?至少
java.util.List
没有产生ClassCastException;这是否意味着这是正确的?我可以从Clojure发送Frege几乎任何Java集合类型,请参阅Converting Clojure data structures to Java collections。
顺便说一句,改用普通的
(Foo/myfregefunction [1,2,3,4])
会产生ClassCastException clojure.lang.PersistentVector cannot be cast to free.runtime.Lazy
,@ Ingo指出:“clojure列表不是frege列表。”转换为java.util.ArrayList
时,响应类似。在Frege方面,代码类似于
module Foo where
myfregefunction :: [Int] -> Int
-- do something with the list here
最佳答案
好的,不知道Clojure,但是从您给我的链接中我认为,您需要给出一个可实例化的类的名称(即java.util.ArraList
),因为java.util.List
只是一个接口,因此无法构造。
对于Frege端(在这种情况下为使用者),只需假设接口即可。
整个事情变得有些复杂,因为Frege知道Java列表是可变的。这意味着不能存在纯函数
∀ s a. Mutable s (List a) → [a]
并且用纯语言编写此类功能的任何尝试都必须失败,并且将被编译器拒绝。
取而代之的是,我们需要一个
ST
动作来包装纯净的部分(在这种情况下,就是您的函数myfregefunction
)。 ST
是使处理可变数据成为可能的monad。就像这样:import Java.Util(List, Iterator) -- java types we need
fromClojure !list =
List.iterator list >>= _.toList >>= pure . myfregefunction
从clojure,您现在可以调用类似的代码(如果我对clojure的语法有误,请原谅我(欢迎编辑)):
(frege.prelude.PreludeBase$TST/run (Foo/fromClojure (java.util.ArrayList. [1,2,3,4])))
通过Java进行的这种接口有两个缺点,恕我直言。首先,我们介绍了可变性,Frege编译器不允许我们忽略它,因此接口变得更加复杂。此外,列表数据将被复制。我不知道Clojure的工作方式,但是至少在Frege方面,有这段代码遍历了迭代器并将数据收集到Frege列表中。
因此,更好的方法是让Frege知道
clojure.lang.PersistentVector
是什么,并直接对Frege中的clojure数据进行操作。我知道有人用clojure持久性哈希映射做到了这一点,所以我想应该可以对列表做同样的事情。(在这一点上,我不得不指出贡献一个经过深思熟虑的Clojure / Frege接口库将是多么有价值!)
编辑:正如来自@ 0dB的自我回答所暗示的那样,他将实现前面段落中提到的高级解决方案。我鼓励每个人都支持这项崇高的事业。
第三种方法是直接在Clojure中构造Frege列表。