根据@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
,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
直接在 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 提出的改进建议。