![](/img/trans.png)
[英]what is the easiest way to pass a list of integers from java to a frege function?
[英]How to pass a list of integers from Clojure to a Frege function?
受上一个问题的启发,将整数列表从java传递给frege函数的最简单方法是什么? @Ingo对答案的评论,我试过了
(Foo/myfregefunction (java.util.List. [1,2,3,4]))
但得到(ctor = constructor):
CompilerException java.lang.IllegalArgumentException: No matching ctor found for interface java.util.List
有任何想法吗? 至少java.util.List
没有产生ClassCastException; 这是否意味着这是正确的轨道?
我可以从Clojure发送几乎任何Java集合类型的Frege,请参阅将Clojure数据结构转换为Java集合 。
顺便说(Foo/myfregefunction [1,2,3,4])
,使用plain (Foo/myfregefunction [1,2,3,4])
而不是产生ClassCastException clojure.lang.PersistentVector cannot be cast to free.runtime.Lazy
,@ Ingo指出,“一个clojure列表不是frege list。“作为java.util.ArrayList
转换时的类似响应。
在弗雷格方面,代码就像
module Foo where
myfregefunction :: [Int] -> Int
-- do something with the list here
好的,不知道Clojure,但是从你给出的链接我得到它你需要给出一个可实例化的类的名称(即java.util.ArraList
),因为java.util.List
只是一个接口,因此无法构造。
对于弗雷格方面,在这种情况下是消费者,它就足以假设接口。
整个事情变得有点复杂,因为弗雷格知道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列表。
根据@Ingo的回答,
更好的方法是让Frege知道clojure.lang.PersistentVector是什么,并直接在Frege的clojure数据上工作。
和评论以及Adam Bard的PersistentMap解决方案,我提出了一个有效的解决方案:
module foo.Foo where
[编辑]正如Ingo指出的那样,作为ListView的一个实例给我们列表理解,头部,尾部......
instance ListView PersistentVector
我们需要注释一个用于Frege的Clojure类( pure native
基本上使得Frege可以使用Java方法而不需要任何monad来处理可变性,因为 - 通常 - 数据在Clojure中也是不可变的):
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
现在,遵循一些添加到此数据类型的函数,用于从Frege列表创建Clojure向量,或者反过来:
fromList :: [a] -> PersistentVector a
fromList = fold cons empty
toList :: PersistentVector a -> [a]
toList pv = map pv.valAt [0..(pv.length - 1)]
注意我使用“点”符号; 看看@Dierk的优秀文章, 点的力量 。
[编辑]对于ListView
(以及Frege with PersistentVector
一些乐趣),我们还需要实现uncons
, null
和take
(抱歉这里有快速和脏的解决方案;我会尽快解决这个问题):
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
在我上面的快速和肮脏的解决方案,注意使用PreludeList.take
避免调用take
在命名空间PersistentVector
造成的,我怎么没有前缀fromList
, toList
, cons
和empty
。
有了这个设置(你可以离开了uncons
, null
和take
还有instance
声明顶部,如果你不想用做什么PersistentVector
弗雷格直接),你现在可以调用弗雷格函数,它接受并返回一个列表正确包装:
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函数,请确保类型签名“匹配”,例如PersistentVector a
匹配[a]
。
前进:我这样做是因为我想把我的一些Clojure程序移植到Frege,“一次一个功能”。 我相信我会遇到一些我需要研究的更复杂的数据结构,而且,我仍在研究Ingo提出的改进建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.