Java 如何将整数列表从Clojure传递到Frege函数?

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

受上一个问题和@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])
会产生
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函数,请确保类型签名“匹配”,例如。g
PersistentVector 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