Java 如何将整数列表从Clojure传递到Frege函数?
受上一个问题和@Ingo回答中的一条评论的启发,我尝试了Java 如何将整数列表从Clojure传递到Frege函数?,java,clojure,frege,Java,Clojure,Frege,受上一个问题和@Ingo回答中的一条评论的启发,我尝试了 (Foo/myfregefunction (java.util.List. [1,2,3,4])) 但是get(ctor=constructor): 有什么想法吗?至少java.util.List没有产生ClassCastException;这是否意味着这是在正确的轨道上 我可以从Clojure向Frege发送几乎任何Java集合类型,请参阅 顺便说一句,使用普通的(Foo/myfregefunction[1,2,3,4])会产生Cla
(Foo/myfregefunction (java.util.List. [1,2,3,4]))
但是get(ctor=constructor):
有什么想法吗?至少java.util.List
没有产生ClassCastException;这是否意味着这是在正确的轨道上
我可以从Clojure向Frege发送几乎任何Java集合类型,请参阅
顺便说一句,使用普通的(Foo/myfregefunction[1,2,3,4])
会产生ClassCastException clojure.lang.PersistentVector不能强制转换为free.runtime.Lazy
,@Ingo指出,“clojure列表不是frege列表。”当强制转换为java.util.ArrayList
时,类似的响应
在弗雷格方面,代码类似于
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
是使处理可变数据成为可能的单子。这将是这样的:
import Java.Util(List, Iterator) -- java types we need
fromClojure !list =
List.iterator list >>= _.toList >>= pure . myfregefunction
从clojure,您现在可以调用如下内容(如果我的clojure语法错误,请原谅(欢迎编辑)):
这种通过Java的接口有两个缺点,IMHO。首先,我们引入了易变性,Frege编译器不允许我们忽略这一点,因此接口变得更加复杂。此外,列表数据将被复制。我不知道Clojure是如何做到的,但在Frege方面,至少有这样一段代码经过迭代器并将数据收集到Frege列表中
因此,更好的方法是让Frege知道什么是clojure.lang.PersistentVector
,并直接处理Frege中的clojure数据。我知道有人用clojure持久散列映射这样做,所以我想对列表也可以这样做
(在这一点上,我不得不指出,贡献一个深思熟虑的Clojure/Frege接口库是多么有价值!)
编辑:正如@0dB的自我回答所暗示的,他即将实施前面段落中提到的高级解决方案。我鼓励每个人以投票支持这一崇高事业
第三种方法是直接在Clojure中构建Frege列表。基于@Ingo的答案 更好的方法是让Frege知道clojure.lang.PersistentVector是什么,并直接处理Frege中的clojure数据 以及Adam Bard的PersistentMap解决方案,我提出了一个可行的解决方案:
module foo.Foo where
[编辑]正如Ingo所指出的,作为ListView的一个实例,我们可以理解列表、头、尾
instance ListView PersistentVector
我们需要为Frege中使用的Clojure类添加注释(pure native
基本上使Java方法对Frege可用,而不需要任何monad来处理可变性,这是可能的,因为一般来说,Clojure中的数据也是不可变的):
现在,以下是添加到此数据类型的函数,用于从Frege list或其他方法创建Clojure向量:
fromList :: [a] -> PersistentVector a
fromList = fold cons empty
toList :: PersistentVector a -> [a]
toList pv = map pv.valAt [0..(pv.length - 1)]
注意我使用的“点”符号;请参阅@Dierk的优秀文章
[编辑]对于列表视图
(以及Frege在PersistentVector
中的一些乐趣),我们还需要实现uncon
、null
和take
(很抱歉这里的解决方案太快了,我会尽快解决这个问题):
在我上面的快速而肮脏的解决方案中,请注意使用了PreludeList.take
以避免在PersistentVector
创建的命名空间中调用take
,以及我如何不必在fromList
、toList
、cons
和empty
前加前缀
使用此设置(您可以省略uncon
、null
和take
以及顶部的实例
声明,如果您不想直接在Frege中使用PersistentVector
执行任何操作),现在可以调用Frege函数,该函数通过正确包装列表来获取并返回列表:
fromClojure :: PersistentVector a -> PersistentVector a
fromClojure = PersistentVector.fromList • myfregefn • PersistentVector.toList
-- sample (your function here)
myfregefn :: [a] -> [a]
myfregefn = tail
在Clojure中,我们只需调用(foo.foo/fromClojure[1 2 3 4])
,并通过myfregefn
所做的任何处理(在本例中[2 3 4]
)获取Clojure向量。如果myfregefn
返回Clojure和Frege都能理解的内容(String
,Long
,…),则省略PersistentVector.fromList
(并修复类型签名)。尝试使用上述两种方法,tail
返回列表,使用head
返回,例如Long
或String
对于包装器和Frege函数,请确保类型签名“匹配”,例如。gPersistentVector a
匹配[a]
前进:我这样做是因为我想把我的一些Clojure程序移植到Frege,“一次一个函数”“。我确信我将遇到一些更复杂的数据结构,我将不得不研究,而且,我仍在研究Ingo提出的改进建议。只是为了完整性:您还应该能够使用Clojure的
来排列,并将其作为弗雷格方面的JArray a
。这很好。”当您可以直接处理数组时,但如果您需要列表API进行处理,这可能不是最有效的方法。无需调用(java)。
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
fromList :: [a] -> PersistentVector a
fromList = fold cons empty
toList :: PersistentVector a -> [a]
toList pv = map pv.valAt [0..(pv.length - 1)]
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
fromClojure :: PersistentVector a -> PersistentVector a
fromClojure = PersistentVector.fromList • myfregefn • PersistentVector.toList
-- sample (your function here)
myfregefn :: [a] -> [a]
myfregefn = tail