4

受上一个问题的启发,将整数列表从 java 传递给 frege 函数的最简单方法是什么?并在@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 集合类型,请参阅将 Clojure 数据结构转换为 Java 集合

顺便说一句,使用 plain(Foo/myfregefunction [1,2,3,4])代替 yield ClassCastException clojure.lang.PersistentVector cannot be cast to free.runtime.Lazy,@Ingo 指出,“clojure 列表不是 frege 列表。” 转换为 时的类似响应java.util.ArrayList

在弗雷格方面,代码类似于

module Foo where

myfregefunction :: [Int] -> Int
-- do something with the list here
4

2 回答 2

5

好的,不知道 Clojure,但是从您提供的链接中,我认为您需要提供可实例化类的名称(即java.util.ArraList),因为java.util.List它只是一个接口,因此无法构造。

对于 Frege 方,在这种情况下是消费者,假设接口就足够了。

整个事情变得有点复杂,因为 Frege 知道 java 列表是可变的。这意味着不存在纯函数

∀ s a. Mutable s (List a) → [a]

用纯语言编写这样一个函数的每一次尝试都必须失败,并且会被编译器拒绝。

相反,我们需要的是ST包装纯部分的操作(在本例中为您的 function 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 进行的接口有两个缺点,恕我直言。一方面,我们引入了可变性,弗雷格编译器不允许我们忽略它,因此接口变得更加复杂。此外,列表数据将被复制。我不知道 Clojure 是如何做到的,但至少在 Frege 方面,有这段代码遍历迭代器并将数据收集到 Frege 列表中。

因此,更好的方法是让 Frege 了解 aclojure.lang.PersistentVector是什么,并直接在 Frege 中处理 clojure 数据。我知道有人用 clojure 持久哈希映射这样做了,所以我想应该可以对列表做同样的事情。

(在这一点上,我不得不指出,贡献一个经过深思熟虑的 Clojure/Frege 接口库是多么有价值!)

编辑:正如@0dB 的自我回答所暗示的那样,他即将实施前面段落中提到的卓越解决方案。我鼓励每个人都以赞成票来支持这项崇高的事业。

第三种方法是直接在 Clojure 中构建 Frege 列表。

于 2015-12-20T09:39:54.337 回答
1

根据@Ingo 的回答,

更好的方法是让 Frege 了解 clojure.lang.PersistentVector 是什么,并直接处理 Frege 中的 clojure 数据。

并对其评论以及 Adam Bard 的 PersistentMap 解决方案,我想出了一个可行的解决方案:

module foo.Foo where

[编辑] 正如 Ingo 所指出的,作为 ListView 的一个实例给了我们列表理解、头部、尾部……</p>

instance ListView PersistentVector

我们需要注释一个 Clojure 类以在 Frege 中使用(pure native基本上使 Java 方法对 Frege 可用,而不需要任何 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 中的一些乐趣PersistentVector),我们还需要实现uncons,nulltake(对于这里的快速和肮脏的解决方案,我很抱歉;我会尽快解决这个问题):

  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我如何不必前缀fromListtoList和.consempty

使用此设置(您可以省略unconsnull以及顶部takeinstance声明,如果您不想PersistentVector直接在 Frege 中执行任何操作),您现在可以调用一个 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])并获取一个 Clojure 向量,然后进行任何处理myfregefn(在本例中[2 3 4])。如果myfregefn返回 Clojure 和 Frege 都能理解的内容 ( String, Long, ...),则省略PersistentVector.fromList(并修复类型签名)。尝试这两种方法,tail如上返回列表和head返回,例如 aLong或 a String

对于包装器和您的 Frege 函数,请确保类型签名“匹配”,例如PersistentVector a匹配[a]

前进:我这样做是因为我想将我的一些 Clojure 程序移植到 Frege,“一次一个函数”。我确信我会遇到一些我必须研究的更复杂的数据结构,而且我仍在研究 Ingo 提出的改进建议。

于 2016-01-01T15:48:01.713 回答