簡體   English   中英

如何將Clojure中的整數列表傳遞給Frege函數?

[英]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一些樂趣),我們還需要實現unconsnulltake (抱歉這里有快速和臟的解決方案;我會盡快解決這個問題):

  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造成的,我怎么沒有前綴fromListtoListconsempty

有了這個設置(你可以離開了unconsnulltake還有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都理解的內容( StringLong ,...),則省略PersistentVector.fromList (並修復類型簽名)。 嘗試既出, tail如上面取回一個列表, head為取回,也就是說,一個LongString

對於包裝器和Frege函數,請確保類型簽名“匹配”,例如PersistentVector a匹配[a]

前進:我這樣做是因為我想把我的一些Clojure程序移植到Frege,“一次一個功能”。 我相信我會遇到一些我需要研究的更復雜的數據結構,而且,我仍在研究Ingo提出的改進建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM